I'm looking for some pointers on how I can fix how my data is being visualized as a bar chart. I've created a small multiples visualization of data that appears over time. Because of the nature of the way the data was collected, the data shares certain attributes. By way of example, you can see an excerpt of the .csv below where group
and date
are repeated:
group,date,totals
acid,1641,8438
acid,1641,0
acid,1641,0
beef,1641,977.85
beef,1641,0
beef,1641,0
beef,1641,164
beef,1641,5.25
bird,1641,121
bird,1641,0
bird,1641,12
bird,1641,1558
bird,1641,729
bird,1641,1680
bird,1641,0
bird,1641,343
bird,1641,3
bird,1641,2092
bird,1641,0
bird,1641,0
bird,1641,107
bird,1641,2679
bird,1641,167
bird,1641,649
boar,1641,41
boar,1641,13
cheese,1641,13
cheese,1641,22
cheese,1641,1071
cheese,1641,17195
(You can see the entire dataset here.)
The problem I'm running in to is wherever a date
is shared, instead of summing the totals
column it stacks the data on top of one another. For example, see:
What I'm struggling with is having the data displayed as a single bar chart. (I have a secondary problem with the y-axis not scaling correctly). I've tried to use nest to fix the problem of the years (this worked for groups
) but I can't seem to get it with date
.
Here's my code, thus far:
var margin = {top: 20, right: 30, bottom: 30, left: 50},
width = 400 - margin.right - margin.left,
height = 150 - margin.top - margin.bottom,
parse = d3.time.format("%Y").parse;
// scales
var x = d3.time.scale().range([0, width]),
y = d3.scale.linear().range([0, height]),
yscaled = d3.scale.linear().range([height, 0]);
// load data
d3.csv("revised.csv", function(error, data) {
// nest values by group
var groups = d3.nest()
.key(function(d) { return d.group; })
.entries(data);
// parse dates and numbers, assume values are sorted by date
// compute the maximum totals per group
groups.forEach(function(s) {
s.values.forEach(function(d) { d.date = parse(d.date); d.totals = +d.totals; });
s.maxtotals = d3.max(s.values, function(d) { return d.totals; });
});
// compute the minimum and maximum date across groups
x.domain([
d3.min(groups, function(s) { return s.values[0].date; }),
d3.max(groups, function(s) { return s.values[s.values.length - 1].date; })
]);
// y.domain([0, d3.max(data, function(d) { return d.totals; })]);
// add an SVG element for each group
var svg = d3.select("body").selectAll("g")
.data(groups)
.enter().append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
var canvas_g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.each(function(d) {
var g = d3.select(this);
g.append("g");
// .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
y.domain([0, d3.max(d.values, function(r) { return r.totals; })]);
yscaled.domain([0, d3.max(d.values, function(r) { return r.totals; })]);
// Draw the charts.
g.selectAll("rect.aevents")
.data(d.values)
.enter().append("rect")
.attr("height", function(p) {return y(p.totals)})
.attr("width", 5)
.attr("x", function(p, q) {return x(p.date)})
.attr("y", function(p) {return height - y(p.totals)})
// .on("click", function(p) {console.log(p.date)})
.attr("class", "bar");
});
// draw x axis
canvas_g.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.svg.axis().scale(x).orient("bottom"));
// draw y axis
canvas_g.append("g")
.attr("class", "y axis")
.call(d3.svg.axis().scale(yscaled).orient("left"));
// add a small label for the group name
svg.append("text")
.attr("x", width + 40)
.attr("y", height + 15)
.attr("text-anchor", "end")
.text(function(d) { return d.key; });
});
Is there a different way I should loop through the data? Or, do I need to restructure the data somehow? Thank you in advance!