elkHunter
elkHunter

Reputation: 55

DC.js bar chart with date axis

I would like to create a bar chart based on dates in x-axis. Labels should be displayed as month (i.e. Jan, Jan'17 - preferred). Within my data I have always first date of following months, i.e. 01Jan, 01Feb, 01Mar. I have created a chart but I am not able to make it aligned.

var chart   = dc.barChart("#" + el.id);
var chCategory = ndx.dimension(function(d) {return d[chCategoryName];});
chValues = chCategory.group().reduceSum(
   return parseFloat(d[chValueName]);});


//set range for x-axis
var minDate = chCategory.bottom(1)[0][chCategoryName];
var maxDate = chCategory.top(1)[0][chCategoryName];
chart
  .width(800)
  .height(200)
  .x(d3.time.scale().domain([minDate,maxDate]))
  .xUnits(d3.time.months)
  .dimension(chCategory)
  .group(chValues)

  .renderHorizontalGridLines(true)
// .centerBar(true) //does not look better
   .controlsUseVisibility(true)
   .ordinalColors(arrColors) 
   .transitionDuration(1000)
   .margins({top: 10, left: 80, right: 5, bottom: 20})

Chart Preview

I have already read post: dc.js x-axis will not display ticks as months, shows decimals instead but I am not able to implement it in a way that will keep correct sorting for different years.

Upvotes: 4

Views: 3895

Answers (1)

Gordon
Gordon

Reputation: 20120

dc.js takes the domain pretty literally - the x axis stretches exactly from the beginning to the end, disregarding the width of the bars or their placement. It's a design bug.

Here are two workarounds.

keep bars centered and add padding

If you're using elasticX you can manually correct it like this:

chart.centerBar(true)
    .xAxisPadding(15).xAxisPaddingUnit('day')

If you're just setting the domain manually, that's

minDate = d3.time.day.offset(minDate, -15);
maxDate = d3.time.day.offset(maxDate, 15);

align the ticks to the left of bars and correct the right side of the domain

You don't say what problem you run into when you don't center the bars. But I know the right bar can get clipped.

If you want the elasticX effect, you can implement it manually like this, offsetting the right side by a month (example):

function calc_domain(chart) {
    var min = d3.min(chart.group().all(), function(kv) { return kv.key; }),
        max = d3.max(chart.group().all(), function(kv) { return kv.key; });
    max = d3.time.month.offset(max, 1);
    chart.x().domain([min, max]);
}
chart.on('preRender', calc_domain);
chart.on('preRedraw', calc_domain);

Or without elasticX that's just:

maxDate = d3.time.month.offset(maxDate, 1);

Upvotes: 5

Related Questions