Accepted answer

This answer expands on @Gerardo's solution, making the chart adjust dynamically, and dealing with a few dc.js quirks.

First, the original author of this example fudged a few things just to get stuff working. If you want truly dynamic axes, you'll need to show dc.js how to calculate the bar widths for itself:


and remove .gap(65) - that kind of magic number is always a sign that someone couldn't figure out how to get things calculated automatically.

There are a few quirks with how dc.js deals with bar charts. For one, it doesn't really account for its own bar width or centering when it sets the domain - it uses exactly what you give it. You'll notice that the rightmost bar is missing when automatically calculating the maximum. (This happens with elasticX(true) too.)

So let's turn off bar-centering and add the 0.1 bar width to the domain each time we calculate it.

  .x(d3.scale.linear().domain([2, d3.max(data, d=>d.mag)+0.1]))

Next, crossfilter does not automatically remove empty bins, so we can wrap the group in a fake group to do that:

function remove_empty_bins(source_group) {
    return {
        all:function () {
            return source_group.all().filter(function(d) {
                return d.value != 0;


And we can have the chart recalculate its domain every time it's redrawn like so:

.on('preRedraw', function(chart) {
  chart.x().domain([2, d3.max(, kv=>kv.key) + 0.1]);

Fork of the block:


Change this line:

.x(d3.scale.linear().domain([0.5, 7.5]))


.x(d3.scale.linear().domain([2, d3.max(data, d=>d.mag)]))

Related Query