1

I have a very similar question as the one posted here: how to create multiline chart using dc.js

I am new to stackoverflow, which means that I am unable to add comments or I would have asked for additional information on that post. So, I apologize for any redundancy.

I have data structured like:

var data = {
  {"id": 'id_value1', ..., "dates": {"name": {"d1":"  0-91","d2":" 92-182","d3":"183-273","d4":"274-364","d5":"365+"}, "value": {"v1":'A',"v2":'A',"v3":'C',"v4":'D',"v5":'B'}},
  {"id": 'id_value2', ..., "dates": {"name": {"d1":"  0-91","d2":" 92-182","d3":"183-273","d4":"274-364","d5":"365+"}, "value": {"v1":'A',"v2":'B',"v3":'D',"v4":'C',"v5":'A'}},
  ...
  {"id": 'id_valueN', ..., "dates": {"name": {"d1":"  0-91","d2":" 92-182","d3":"183-273","d4":"274-364","d5":"365+"}, "value": {"v1":'A',"v2":'A',"v3":'A',"v4":'-',"v5":'-'}}
}

I would like to create a bar graph that has "0-91","92-182","183-273","274-364","365+" as the x-axis variables. I also want to have it stacked such that each layer is a count for each individual letter (A,B,C,D). The data is stored such that d1 is the corresponding date for the v1 value, v2 is the value for date d2, and so on. In other words,

id         ...  0-91  92-182  183-273  274-364  365+
id_value1  ...  A     A       C        D        B
id_value2  ...  A     B       D        C        A
...
id_valueN  ...  A     A       A        -        -

I would post a picture of what I want, but again (since I am so new) I am unable to. I know it would make more sense to see what I am asking for.

I have tried:

var ndx = crossfilter(data);  // all data
var dim = ndx.dimension(function(d) {return d.id;});
var group1 = dim.group().reduceCount(function(d) {return d.dates.value.v1;});
var group2 = dim.group().reduceCount(function(d) {return d.dates.value.v2;});
var group3 = dim.group().reduceCount(function(d) {return d.dates.value.v3;});
var group4 = dim.group().reduceCount(function(d) {return d.dates.value.v4;});
var group5 = dim.group().reduceCount(function(d) {return d.dates.value.v5;});
var compositeChart = dc.compositeChart("#bar")
    .width(1850).height(150)
    .dimension(dim)
    .group(group1)
    .valueAccessor(function(d) {return d.value;})
    .x(d3.scale.ordinal())
    .xUnits(dc.units.ordinal)
    .compose([
        dc.barChart(compositeChart).group(group1).gap(10),
        dc.barChart(compositeChart).group(group2).gap(10),
        dc.barChart(compositeChart).group(group3).gap(10),
        dc.barChart(compositeChart).group(group4).gap(10),
        dc.barChart(compositeChart).group(group5).gap(10)
    ]);

But that doesn't work. The closest I have managed to get to what I want is to create 5 different graphs, one for each date. The following bit of code demonstrates this:

var chart1 = dc.barChart("#chart1");
var dim1 = ndx.dimension(function(d) {return d.dates.name.d1;});
var A1 = dim1.group().reduceSum(function(d) {if(d.dates.value.v1 === "A"){return +1;}else{return 0;}});
var B1 = dim1.group().reduceSum(function(d) {if(d.dates.value.v1 === "B"){return +1;}else{return 0;}});
var C1 = dim1.group().reduceSum(function(d) {if(d.dates.value.v1 === "C"){return +1;}else{return 0;}});
var D1 = dim1.group().reduceSum(function(d) {if(d.dates.value.v1 === "D"){return +1;}else{return 0;}});

var chart2 = dc.barChart("#chart2");
var dim2 = ndx.dimension(function(d) {return d.dates.name.d2;});
var A2 = dim2.group().reduceSum(function(d) {if(d.dates.value.v2 === "A"){return +1;}else{return +0;}});
var B2 = dim2.group().reduceSum(function(d) {if(d.dates.value.v2 === "B"){return +1;}else{return +0;}});
var C2 = dim2.group().reduceSum(function(d) {if(d.dates.value.v2 === "C"){return +1;}else{return +0;}});
var D2 = dim2.group().reduceSum(function(d) {if(d.dates.value.v2 === "D"){return +1;}else{return +0;}});

...

var chart5 = dc.barChart("#chart5");
var dim5 = ndx.dimension(function(d) {return d.dates.name.d5;});
var A5 = dim5.group().reduceSum(function(d) {if(d.dates.value.v5 === "A"){return +1;}else{return 0;}});
var B5 = dim5.group().reduceSum(function(d) {if(d.dates.value.v5 === "B"){return +1;}else{return 0;}});
var C5 = dim5.group().reduceSum(function(d) {if(d.dates.value.v5 === "C"){return +1;}else{return 0;}});
var D5 = dim5.group().reduceSum(function(d) {if(d.dates.value.v5 === "D"){return +1;}else{return 0;}});

chart1
    .width(110).height(450)
    .dimension(dim1)
    .group(A5, "A's")
    .stack(B5, "B's")
    .stack(C5, "C's")
    .stack(D5, "D's")
    .y(d3.scale.linear().domain([minAll,maxAll]))
    .x(d3.scale.ordinal())
    .xUnits(dc.units.ordinal)
    .elasticY(false)
    .yAxisLabel("count")
    .ordinalColors(["#008600","#80FF80","#FF80FF","#860086"])
    .margins({top:20, left:60, right:10, bottom:120});

chart2
    .width(50).height(450)
    .dimension(dim2)
    .group(A2, "A's")
    .stack(B2, "B's")
    .stack(C2, "C's")
    .stack(D2, "D's")
    .y(d3.scale.linear().domain([minAll,maxAll]))
    .x(d3.scale.ordinal())
    .xUnits(dc.units.ordinal)
    .elasticY(false)
    .ordinalColors(["#008600","#80FF80","#FF80FF","#860086"])
    .margins({top:20, left:-1, right:10, bottom:120});

...

chart5
    .width(50).height(450)
    .dimension(dim5)
    .group(A5, "A's")
    .stack(B5, "B's")
    .stack(C5, "C's")
    .stack(D5, "D's")
    .y(d3.scale.linear().domain([minAll,maxAll]))
    .x(d3.scale.ordinal())
    .xUnits(dc.units.ordinal)
    .elasticY(false)
    .ordinalColors(["#008600","#80FF80","#FF80FF","#860086"])
    .margins({top:20, left:-1, right:10, bottom:120});

The problem with this is that these 5 graphs either won't have the same flexible y-axis or have the same non-flexible y-axis. I want to be able to click on other graphs in the dashboard with the result being that all graphs in the dashboard are updated to include/exclude the selection. This I don't have an issue with. I just can't create this stacked bar graph. I wanted to give reason to why I need the y-axis to be flexible.

I am using d3.js, dc.js, and crossfilter.js. The data is stored in a JSON file and is included in the html as a source file. Now that you have all the background information, I will ask my question.

How do I define the chart's dimension and group for this type of data to create the bar chart I desire?

Community
  • 1
  • 1
Casey
  • 73
  • 9
  • It can probably be done this way, but it will be lot easier if you can flatten your data so it's just one value per row. Since crossfilter filters on rows, you are not going to be able to filter by date with the current data shape. – Gordon Oct 05 '15 at 11:02
  • The problem with making multiple rows is that the id gets counted multiple times for other graphs in the dashboard. I want all graphs to pull from the same set so that they can update each other when selections are made. – Casey Oct 05 '15 at 13:51
  • But do you want to filter on dates? I don't see how you can do that when the dates are columns. I'm not sure, but I think [reductio](https://github.com/esjewett/reductio) may have some tricks for avoiding the multiple counting. – Gordon Oct 05 '15 at 14:39
  • I ended up solving my issue with some cleaver data management, adding extra counting columns (in order to use reduceSum instead of reduceCount) – Casey Oct 09 '15 at 14:45
  • Thanks for all your suggestions! – Casey Oct 09 '15 at 14:45

0 Answers0