I'd start by considering a slightly larger example data set where you
have more than one question. Here's a list of responses, where each
response has the name of the responder, a question identifier (a
number), and the answer given:
var responses = [
{name: "Adam", question: 1, answer: "Yes"},
{name: "Adam", question: 2, answer: "Yes"},
{name: "Bill", question: 1, answer: "Yes"},
{name: "Bill", question: 2, answer: "No"},
{name: "Chas", question: 1, answer: "Yes"},
{name: "Chas", question: 2, answer: "Yes"}
];
We also define the set of allowed answers. We'll assume here that all
the questions have the same set of responses:
var answers = ["Yes", "No"];
First we define a function that will group the responses by question:
function nest() {
return d3.nest()
.key(function(d) { return d.question; })
.entries(responses);
}
If I call nest(), I get back an array, with one element per question.
The `key` is the question number (1 or 2) and the `values` are the
individual responses for that question. Something like this:
[
{
key: 1,
values: [
{name: "Adam", question: 1, answer: "Yes"},
{name: "Bill", question: 1, answer: "Yes"},
{name: "Chas", question: 1, answer: "Yes"}
]
},
{
key: 2,
values: [
{name: "Adam", question: 2, answer: "Yes"},
{name: "Bill", question: 2, answer: "No"},
{name: "Chas", question: 2, answer: "Yes"}
]
}
]
Next we define a function that, given one of these elements (a
question), computes the count of responses for each of the allowed
answer. This is the cross operator:
function cross(question) {
var counts = d3.nest()
.key(function(d) { return d.answer; })
.rollup(function(d) { return d.length; })
.map(question.values);
return answers.map(function(d) {
return {
answer: d,
count: counts[d] || 0
};
});
}
We first use the nest operator to compute a map from answer to count,
but the count will be undefined if there was no response with a
particular answer. That's why there's an "|| 0" there to convert the
undefined to zero.
Putting it all together:
var ul = d3.select("body").selectAll("ul")
.data(nest)
.enter().append("ul");
ul.append("li")
.text(function(d) { return "Question #" + d.key; });
var li = ul.selectAll("li.answer")
.data(cross)
.enter().append("li")
.attr("class", "answer")
.text(function(d) { return d.answer + ": " + d.count; });
Mike