Dc.js digital chart series

I am trying to create 2 charts for one bar and one series, in which the bar will display the total income for each store and series, showing multi-line income per year.

Here is jsfiddle https://jsfiddle.net/xc4bwgLj/

So, when I click on the β€œBar chart Store 1”, I want the series chart to see that this store will earn 2017 and 2016 each on a new line. Currently, the series chart shows the total revenue for each store, for example, a graph.

Any idea how I can change the series chart to show the revenue for 2016 and 2017 in the store?

JsFiddle Code:

// generate data var data = []; var n = 1000.; for (var i = 0; i < n; i++) { console.log(Math.floor(Math.random() * (1 - 0 + 1)) + 0); data.push({ id: (Math.floor(Math.random() * (1 - 0 + 1)) + 0), "i": i, x: Math.random(), "store_name": "Store"+(Math.floor(Math.random() * (1 - 0 + 1)) + 0), "2017_earnings": Math.random()*110, "2016_earnings": Math.random()*80 }); } // do some crossfilter stuff var cf = crossfilter(data), series = cf.dimension(function(d) { return [d.store_name, di]; }), series_grouped = series .group(function(d) { console.log(d) return [d[0], Math.floor(d[1] / 100.) * 100.]; }) .reduceSum(function(d) { return dx; }), id = cf.dimension(function(d) { return d.store_name; }), id_grouped = id.group().reduceSum(function(d) { return dx; }); // generate charts var chart_width = 960, chart_height = 200; console.log(dc); dc.seriesChart("#chart_a").height(chart_height).width(.74 * chart_width) .chart(function(c) { return dc.lineChart(c).renderArea(true) .filterHandler(function(dimension, filter) { if(filter[0]) { dimension.filterFunction(function(d) { return d[1] > filter[0][0] && d[1] < filter[0][1]; }); } else { dimension.filterAll(); } setTimeout(dc.redrawAll,0); return filter; }); }) .x(d3.scale.linear().domain([0, n])) .dimension(series) .group(series_grouped) .seriesAccessor(function(d) { return d.key[0]; }) .keyAccessor(function(d) { return d.key[1]; }) .valueAccessor(function(d) { return d.value; }).legend(dc.legend().x(350).y(350).itemHeight(13).gap(5).horizontal(1).legendWidth(140).itemWidth(70)); dc.barChart("#chart_b").height(chart_height).width(.24 * chart_width) .dimension(id) .group(id_grouped) .x(d3.scale.ordinal()) .xUnits(dc.units.ordinal) .xAxis(); dc.renderAll(); 
+8
source share
2 answers

Here, a solution using a different data form is used. In my other example, a fake group is used to change shape after aggregation.

Using a different form of data.

In this case, I do not think that the data form contributes to what you want to do, so in this answer I will change the form. I will try to use a fake group in the second answer.

The series chart accepts one group with multikeys, and the group filters line by line. Since each line contains both the profitability of 2016 and 2017, it is impossible to combine them separately using crossfilter.

So, for this attempt, I divided the records by year of income:

 for (var i = 0; i < n; i++) { var id = Math.round(Math.random()), x = Math.random(), store = "Store"+Math.round(Math.random()); data.push({ id: id, i: i, x: x, store_name: store, earnings_year: 2016, earnings: Math.random()*80 }); data.push({ id: id, i: i, x: x, store_name: store, earnings_year: 2017, earnings: Math.random()*110, }); } 

I think this preserves all the qualities of your source data, but it breaks down records by year of income. I also simplified the generation of random numbers .; -)

Now we can easily create a multi-chamber dimension that uses earnings_year .

I don’t think that rounding in the key function of the group worked, because the measurement functions and the key groups should be in the same order , so I moved it:

  series = cf.dimension(function(d) { return [d.earnings_year, Math.floor(di / 100.) * 100.]; }), 

Now we simply group the same keys and reduce by the amount of earnings instead of x (which, it seems to me, was intended).

  series_grouped = series.group() .reduceSum(function(d) { return d.earnings; }), 

Fork your violin with filtering by store https://jsfiddle.net/gordonwoodhull/urxLwh81/

+1
source share

Here, a different approach is used that preserves the shape of the source in the same way, but splits the group into using a series chart. In my other answer, I am changing the shape of the source data.

Using fake group

Whenever we need to pre-process data, for example. to change the form that crossfilter returns, we can use a fake group

We will separate both columns separately using the usual reduction of several fields:

  series = cf.dimension(function(d) { return di; }), series_grouped = series.group(function(k) { return Math.floor(k / 100.) * 100.; }) .reduce( function(p, d) { // add p[2016] += d['2016_earnings']; p[2017] += d['2017_earnings']; return p; }, function(p, d) { // remove p[2016] -= d['2016_earnings']; p[2017] -= d['2017_earnings']; return p; }, function() { return {2016: 0, 2017: 0}; }), 

Then this split group will take the names of two fields and split each bit into two, using the field name as the first part of multikey:

 function split_group(group, field1, field2) { return { all: function() { var ret = []; group.all().forEach(function(kv) { ret.push({ key: [field1, kv.key], value: kv.value[field1] }); ret.push({ key: [field2, kv.key], value: kv.value[field2] }); }); return ret; } } } 

Use it as follows:

  series_split = split_group(series_grouped, 2016, 2017) // ... chart .group(series_split) 

It's hard to say with random number generation, but I think the result is identical to the other answer. Just a different approach.

+1
source share

All Articles