I\'m building a bar plot in d3.js in which each bar represents total TB cases during a month. The data essentially consists of a date (initially strings in %Y-%m format, bu
Try d3.scale.ordinal
:
var y = d3.scale.ordinal()
.domain(yourDomain)
.rangeRoundBands([0, chartHeight], 0.2);
Tweek 0.2 parameter.
You can combine ordinal and time scales:
// Use this to draw x axis
var xScaleDate = d3.time.scale()
.domain(d3.extent(thisstat, function(d) { return d.date; }))
.range([0, width - margin.left - margin.right]);
// Add an ordinal scale
var ordinalXScale = d3.scale.ordinal()
.domain(d3.map(thisstat, function(d) { return d.date; }))
.rangeBands([0, width], 0.4, 0);
// Now you can use both of them to space columns evenly:
columnGroup.enter()
.append("rect")
.attr("class", "column")
.attr("width", ordinalXScale.rangeBand())
.attr("height", function (d) {
return height - yScale(d.value);
})
.attr("x", function (d) {
return xScaleDate(d.date);
})
.attr("y", function (d){
return yScale(d.value);
});
I've created an example a while ago to demonstrate this approach: http://codepen.io/coquin/pen/BNpQoO
I had the same problem, I've ended up accepting that some months are longer than others and adjusting the column bar width so that the gap between bars remains constant. So tweaking the barPath function in the crossfilter home page demo (http://square.github.com/crossfilter/ - uses d3) I got something like this:
var colWidth = Math.floor(x.range()[1] / groups.length) - 1;//9;
if (i < n - 1) {
//If there will be column on the right, end this column one pixel to the left
var nextX = x(groups[i+1].key)
colWidth = nextX - x(d.key) - 1;
}
path.push("M", x(d.key), ",", height, "V", yVal, "h",colWidth,"V", height);