dc.js系列图表多行

时间:2017-05-03 16:00:21

标签: d3.js dc.js

我正在尝试创建2个图表,一个酒吧和一个系列,酒吧将显示每个商店的总收入,系列将显示每年的多行收入。

这是jsfiddle https://jsfiddle.net/xc4bwgLj/

因此,当我点击条形图商店1时,我想在系列图表中看到这个商店在2017年和2016年的新收入。目前,系列图表显示了每个商店的总收入,如条形图。

任何想法如何更改系列图表以显示2016年和2017年每家商店的收入?

JsFiddle代码:

// 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, d.i];
  }),
  series_grouped = series
  .group(function(d) {
  console.log(d)
    return [d[0], Math.floor(d[1] / 100.) * 100.];
  })
  .reduceSum(function(d) {
    return d.x;
  }),
  id = cf.dimension(function(d) {
    return d.store_name;
  }),
  id_grouped = id.group().reduceSum(function(d) {
    return d.x;
  });

// 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();

2 个答案:

答案 0 :(得分:1)

这是使用不同数据形状的解决方案。我的另一个例子使用假组来在聚合后改变形状。

使用不同的数据形状。

在这种情况下,我不认为数据的形状有利于你想做什么,所以在这个答案中我会改变形状。我会尝试在第二个答案中使用假组。

系列图表采用一个具有多个键的组,一个组按行筛选。由于每行包含2016年和2017年的收入,因此无法使用crossfilter单独聚合它们。

因此,对于这次尝试,我按收益年度分列了记录:

myuser="$(logname 2>/dev/null)"

我认为这保留了原始数据的所有品质,但它将记录按收入年份分割。我还简化了随机数生成。 ; - )

现在我们可以轻松创建使用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, }); } 的多键维度。

我不认为在组密钥功能中进行舍入是有效的,因为the dimension and group key functions need to have the same ordering,所以我已将其移动了:

earnings_year

现在我们只使用相同的键进行分组,并减少 series = cf.dimension(function(d) { return [d.earnings_year, Math.floor(d.i / 100.) * 100.]; }), 而不是earnings的总和(这是我认为的目的)。

x

小提琴的叉子,按商店https://jsfiddle.net/gordonwoodhull/urxLwh81/过滤

答案 1 :(得分:1)

这是一种不同的方法,可以保持源的形状相同,但拆分组以使用系列图表。在我的另一个答案中,我更改了源数据形状。

使用虚假组

每当我们需要预处理数据时,例如要更改crossfilter返回的形状,我们可以使用fake group

我们将使用普通的多个字段缩减来分别减少两列:

  series = cf.dimension(function(d) {
    return d.i;
  }),
  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};
    }),

然后这个拆分组将获取两个字段的名称,并将每个bin分成两个,使用字段名称作为多键的第一部分:

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;
    }
  }
}

像这样使用:

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

很难用随机数生成,但我认为结果与其他答案相同。只是一种不同的方法。