2016-07-25 6 views
1

Я пытаюсь продолжить создание панели статистики статистики бейсбола и, похоже, снова попал в стену.DC.js Reductio - отображает кумулятивное среднее значений в диапазоне дат DC

У меня есть массив записей, представляющих статистику для игры, и хотел бы создать баркард с одной полосой, которая представляет среднее значение ватин для выбранного диапазона дат в первом графике на странице.

Мне была оказана помощь в создании первой диаграммы, которая показывает суммарное количество хитов за выбранный диапазон дат. Подход состоял в том, чтобы изменить функцию groupAll, чтобы ответить на вызов функции all(), а не на .value(), используя функцию regularize_groupAll.

Подход 1:

При попытке использовать тот же подход, я настроил график/группу, чтобы вычислить общий вклад в общее среднее за каждый день (в этом примере есть три игры, где в среднем за день для нападающего за каждый день составляет 0,500, но из-за разных итогов в хитах и ​​абс, каждая игра вносит разные суммы в суммарное среднее значение). Это нежелательно, потому что я хотел бы, чтобы график показывал фактическое среднее значение для выбранного периода времени (если выбрана одна игра, я хочу, чтобы график показывал .500, то же самое для двух игр, то же самое для всех трех, поскольку совокупное среднее значение для всех возможный дата combos - .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 была попытка создать пользовательские функции уменьшения и подачи их к groupAll() снижения функции (reduceAdd, reduceRemove, reduceInitial).. Сначала эта попытка не создала график. После добавления .valueAccessor (function (p) {return p.value.count> 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

Когда вы вычисляете среднее значение с помощью 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); 
    }); 

Вот Fiddle: https://jsfiddle.net/esjewett/qmtL6221/1/

Обратите внимание, что я не уверен, если ваш в летучей мыши счетчик уже удаляет прогулки или нет.Я предположил, что он включает в себя прогулки и удаляет их, потому что прогулки не учитываются как в летучих мышах в средневзвешенном вычислении, но не делайте этого, если ваш счет в бате не включает прогулки.

P.S. Посмотрите на это немного больше, и ваш подход 3 будет работать. Проблема в том, что, как вы заметили, фильтр не применяется к вашей группе. Это связано с тем, что вы определили свою группу с тем же размером dateDim, что и вы. Crossfilter не применяет фильтры к тому же размеру, на который определен фильтр.