DC.js Reductio - 显示日期范围DC

时间:2016-07-25 12:50:53

标签: d3.js dc.js crossfilter reductio

我正在尝试继续构建一个棒球统计仪表板,似乎又一次撞墙了。

我有一系列代表游戏统计数据的记录,并希望生成一个条形图,其中包含一个条形图,表示页面第一个图表中所选日期范围的击球平均值。

我收到了有关创建第一个图表的帮助,该图表显示了所选日期范围的累计命中总数。方法是使用regularize_groupAll函数更改groupAll函数以响应all()函数调用而不是.value()。

方法1:

当尝试使用相同的方法时,我将图表/组配置为计算每天总平均值的总贡献(在此示例中,有三个游戏,其中每天的击球手的平均值为。但是由于命中和绝对的总数不同,每个游戏对累积平均值的贡献不同。这不是所希望的,因为我希望图表显示所选时间段的实际平均值(如果选择一个游戏,我希望图表显示.500,两个游戏相同,所有三个相同,因为所有三个游戏的累积平均值可能的日期组合是.500)。

var avgChart = dc.barChart("#avg-chart");

function avg(totalAbs, dim) {
  return dim.groupAll().reduceSum(function(d) {
  return (d.h / d.ab) * (d.ab / totalAbs);
 });
}

var totalAbs = abDim.groupAll().reduceSum(function(d){ return d.ab }).value();
var totalAvg = avg(totalAbs, abDim);

var regTotalAvg = regularize_groupAll(totalAvg);
avgChart
 .width(200)
 .height(HEIGHT + 30)
 .x(d3.scale.ordinal().domain(["Avg"]))
 .xUnits(dc.units.ordinal)
 .y(d3.scale.linear().domain([0, totalAvg.value()]))
 .yAxisLabel("")
 .centerBar(true)
 .dimension(abDim)
 .brushOn(false)
 .alwaysUseRounding(true)
 .group(regTotalAvg);

 avgChart.render();

方法2:

在查看Reductio的文档后,我想我可以使用.groupAll(groupingFunction)。部分解决问题的方法是使用该功能将当前日期计算中包含的所有先前日期的游戏。我能够使用.sum(d.h)函数获得正确的命中数,但我目前无法将计数修改为正确的数字(d.ab)。

groupAll = dateDim.groupAll();
var dateArray = [new Date( 2016,3,4) ,new Date( 2016,3,5) ,new Date( 2016,3,6)];

reducer = reductio()
  .groupAll(function(record) {
    var datesToInclude = new Array();
    for(i = record.index; i < dateArray.length; i++) {
      datesToInclude.push(dateArray[i]);
    }
   return datesToInclude;
  })
  .count(true)
  .sum(function(d){ return d.h });

reducer(groupAll);
console.log(groupAll.value());

方法3:

方法3是尝试创建自定义reduce函数并将它们提供给groupAll()。reduce(reduceAdd,reduceRemove,reduceInitial)函数。这种尝试最初没有产生图表。添加.valueAccessor后(函数(p){return p.value.count&gt; 0?p.value.total / p.value.count:0});调用函数的末尾绘制总平均值,但在设置断点后,我发现在移动画笔以过滤日期后,从未调用过reduceRemove函数。

var avgChart = dc.barChart("#avg-chart")

function reduceAdd(p, v) {
  p.count += v.ab;
  p.total += v.h;
  return p;
}

function reduceRemove(p, v) {
 p.count -= v.ab;
 p.toal -= v.h;
 return p;
}

function reduceInitial() {
 return {
  count: 0,
  total: 0
 };
}

var allAvg = dateDim.groupAll().reduce(reduceAdd, reduceRemove, reduceInitial);
var totalAvg = allAvg.value()
console.log("Total avg total hit count" + totalAvg.total)
console.log("Total avg count ab count" + totalAvg.count)
var regTotalAvg = regularize_groupAll(allAvg);

avgChart
 .width(200)
 .height(HEIGHT + 30)
 .x(d3.scale.ordinal().domain(["Avg"]))
 .xUnits(dc.units.ordinal)
 .y(d3.scale.linear().domain([0, totalAvg.total / totalAvg.count]))
 .yAxisLabel("")
 .centerBar(true)
 .dimension(dateDim)
 .brushOn(false)
 .alwaysUseRounding(true)
 .group(regTotalAvg)
 .valueAccessor(function(p) {
  return p.value.count > 0 ? p.value.total / p.value.count : 0
 });

 avgChart.render();

的jsfiddle: https://jsfiddle.net/schins02/acchgsfL/

非常感谢任何帮助,我希望这可以帮助我克服困难,并能够自己解决这种性质的问题。

1 个答案:

答案 0 :(得分:4)

使用Crossfilter计算平均值时,应使用Crossfilter逐步计算组件,然后在显示数据时计算平均值。使用Reductio,您可以通过创建始终具有一个值的虚拟维度,然后基于计算必要组件的维度创建组。在您的示例中:

var avgDim = playerData.dimension(function(d) { return true; });
var avgGroup = avgDim.group();
var reducer = reductio();
reducer.value("ab").sum("ab")
reducer.value("h").sum("h");
reducer.value("bb").sum("bb");
reducer(avgGroup);

avgChart
  .width(200)
  .height(HEIGHT + 30)
  .x(d3.scale.ordinal().domain(["Avg"]))
  .xUnits(dc.units.ordinal)
  .y(d3.scale.linear().domain([0, 1]))
  .yAxisLabel("")
  .centerBar(true)
  .dimension(avgDim)
  .brushOn(false)
  .alwaysUseRounding(true)
  .group(avgGroup)
  .valueAccessor(function(p) {
    return p.value.h.sum / ( p.value.ab.sum - p.value.bb.sum );
  });

这是小提琴:https://jsfiddle.net/esjewett/qmtL6221/1/

请注意,我不确定您的击球计数是否已经移除了步行。我认为它包括步行并将其移除,因为在击球平均计算中,步行不算作击球,但如果您的击球数不包括步行,则不要这样做。

P.S。再多看看这个,你的方法3也可以。问题在于,您注意到,过滤器不会应用于您的组。这是因为您在要过滤的同一维度dateDim上定义了您的论坛。 Crossfilter不会将过滤器应用于定义过滤器的相同维度。