Properly display bin width in barChart using dc.js and crossfilter.js
Asked Answered
W

2

22

I'm making a bar chart using the Dimensional Charting javascript library dc.js, which is based on d3 and crossfilter.

All I want to do is display a histogram with a specified number of bins, this should be easy using the barChart function.

I have an array called data which contains floating-point values between 0 and 90000, and I just want to display the distribution using a histogram with 10 bins.

I use the following code to produce the histogram below:

  var cf = crossfilter(data);
  var dim = cf.dimension(function(d){ return d[attribute.name]; });

  var n_bins = 10;
  var xExtent = d3.extent(data, function(d) { return d[attribute.name]; });
  var binWidth = (xExtent[1] - xExtent[0]) / n_bins;
  grp = dim.group(function(d){return Math.floor(d / binWidth) * binWidth;});
  chart = dc.barChart("#" + id_name);
  chart.width(200)
    .height(180)
    .margins({top: 15, right: 10, bottom: 20, left: 40})
    .dimension(dim)
    .group(grp)
    .round(Math.floor)
    .centerBar(false)
    .x(d3.scale.linear().domain(xExtent).range([0,n_bins]))
    .elasticY(true)
    .xAxis()
    .ticks(4);

histogram

That doesn't really look right: each bar is really skinny! I want a normal looking histogram, where the bars are thick and nearly touch each other, with maybe a couple of pixels of padding between each bar. Any idea what I'm doing wrong?

Weighting answered 3/3, 2013 at 21:43 Comment(0)
C
30

Bar charts in dc.js use the xUnits function to automatically calculate the width of the bars in a histogram based on the range of your x-axis. If you want to set the width to a static value you can use a custom xUnits function for example:

chart.xUnits(function(){return 10;});

This should give you a more fitting width.

Cullan answered 3/3, 2013 at 22:25 Comment(0)
F
4

The suggestion given by user2129903 to use the chart.xUnits() to specify a custom xUnits function is indeed the way to go. I'd like to add to that an example and a bit of an explanation as to choose the return value of that custom function.

The doc says:

This function is expected to return a Javascript array of all data points on x axis, or the number of points on the axis.

That is, assuming you want to make a histogram, you can either directly specify the number of bins or calculate it from your desired bin size and return that from that function. You need to specify this when the numeric keys of your grouping are not successive, equidistant integers.

Here is an example:

<!DOCTYPE html><meta charset="utf-8">
<head>
    <link rel="stylesheet" type="text/css" href="js/dc.css"/>
    <script src="js/crossfilter.js"></script>
    <script src="js/d3.js"></script>
    <script src="js/dc.js"></script>
</head>
<body>
    <div id="chart"></div>
</body>
<script>
    // generate data
    var min_value = 0, max_value = 18, value_range = max_value-min_value;
    var data = [];
    for (var i = 0; i < 1000; i++)
        data.push({x: Math.random()*value_range+min_value});
    // create crossfilter dimension for column x
    var cf = crossfilter(data),
        x = cf.dimension(function(d) {return d.x;});
    // create histogram: group values to `number_of_bins` bins
    var number_of_bins = 10,
        bin_width = value_range/number_of_bins,
        //number_of_bins = value_range/bin_width,
        x_grouped = x.group(
            function(d) {return Math.floor(d/bin_width)*bin_width;});
    // generate chart
    dc.barChart("#chart").dimension(x)
        .group(x_grouped)
        .x(d3.scale.linear().domain([min_value,max_value]))
        // let the bar widths be adjusted correctly
        .xUnits(function(){return number_of_bins;})
        .xAxis();
    dc.renderAll();
</script>

Note that in this example it can also work to retrieve the number of bins or the bins' key values from the group object itself, e.g., like this

// number of bins
chart.xUnits(function(){return x_grouped.all().length;});
// bins' key values
chart.xUnits(function(){return x_grouped.all().map(function(d) {return d.key;});});

This will however fail (i.e., produce the wrong bar width), when there are empty bins.

For reference:

Flu answered 27/4, 2016 at 9:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.