简体   繁体   中英

How to create a stacked bar chart using dc.js?

I'd like to create a stacked bar chart using DC.JS.

I've tried to utilize the documentation from DC.JS ( graph , source code ) to no avail - Below is my attempt ( here is my attempt in jsfiddle ) and my most recent attempt in CodePen .

I'd like the 'Name' as the X axis and 'Type' as the stacks.

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.js"></script>
<script src="https://rawgithub.com/NickQiZhu/dc.js/master/web/js/crossfilter.js"></script>
<script src="https://cdnjs.site44.com/dc2.js"></script>
<div id="chart"></div>

Javascript

var data = [ {"Name":"Abby","Type":"Apple"}, {"Name":"Abby","Type":"Banana"}, {"Name":"Bob","Type":"Apple"} ]

data.forEach(function(x) {
  x.Speed = +x.Type;
});

var ndx = crossfilter(data)

var xdim = ndx.dimension(function (d) {return d.Name;});

function root_function(dim,stack_name) {
    return dim.group().reduce(
  function(p, v) {
    p[v[stack_name]] = (p[v[stack_name]] || 0) + v.Speed;
    return p;}, 
  function(p, v) {
    p[v[stack_name]] = (p[v[stack_name]] || 0) - v.Speed;
    return p;}, 
  function() {
    return {};
  });}

var ydim = root_function(xdim,'Type')

function sel_stack(i) {
return function(d) {
  return d.value[i];
};}

var chart = dc.barChart("#chart");

chart
  .x(d3.scale.ordinal().domain(xdim))
  .dimension(xdim)
  .group(ydim, "1", sel_stack('1'))
  .xUnits(dc.units.ordinal);

for(var i = 2; i<6; ++i)
  chart.stack(ydim, ''+i, sel_stack(i));

chart.render();

I've been fiddling with this for some time and I have some additional findings:

I believe the root issue lies in the root_function.

v.Speed is always NaN in your current example. Because +x.Type attempts to convert a string like "Apple" into a number and fails. If you just want to count, then add or subtract 1 in your reducer, rather than v.Speed . Then you need to update your sel_stack code and chart code to handle this change, of course.

Here's a working example for the 2 types in your data. You'll have to update it to handle arbitrary numbers of types, probably by building an array of all your types up front and then looping through it to add stacks to the chart: http://codepen.io/anon/pen/GjjyOv?editors=1010

var data = [ {"Name":"Abby","Type":"Apple"}, {"Name":"Abby","Type":"Banana"}, {"Name":"Bob","Type":"Apple"} ]

var ndx = crossfilter(data)

var xdim = ndx.dimension(function (d) {return d.Name;});

In the reducer, just add and subtract 1 to count:

var ydim = xdim.group().reduce(
  function(p, v) {
    p[v.Type] = (p[v.Type] || 0) + 1;
    return p;}, 
  function(p, v) {
    p[v.Type] = (p[v.Type] || 0) - 1;
    return p;}, 
  function() {
    return {};
  });

sel_stack no longer takes a number, but a key:

function sel_stack(valueKey) {
return function(d) {
  return d.value[valueKey];
};}

var chart = dc.barChart("#chart");

Here we hard-code the stack key, for the purpose of the example:

chart
  .x(d3.scale.ordinal().domain(xdim))
  .dimension(xdim)
  .group(ydim, "Apple", sel_stack('Apple'))
  .xUnits(dc.units.ordinal);

Again, the other hard-coded stack key. You'll need to recreate the loop after creating some sort of data structure that holds all of your stack values.

//for(var i = 2; i<6; ++i)
  chart.stack(ydim, 'Banana', sel_stack('Banana'));

chart.render();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM