2016-07-25 13 views
1

Ich versuche, ein Baseball-Statistik-Dashboard weiter zu bauen und scheinen wieder eine Wand getroffen zu haben.DC.js Reductio - Anzeige kumulativen Durchschnitt der Werte innerhalb des Datumsbereichs DC

Ich habe eine Reihe von Datensätzen, die Statistiken für ein Spiel darstellen und möchte ein Balkendiagramm mit einem einzelnen Balken erstellen, der den Batting-Durchschnitt für den ausgewählten Datumsbereich im ersten Diagramm auf der Seite darstellt.

Ich habe Hilfe beim Erstellen des ersten Diagramms erhalten, das die kumulative Treffermenge für den ausgewählten Datumsbereich anzeigt. Der Ansatz bestand darin, die Funktion groupAll so zu ändern, dass sie mit der Funktion "regularize_groupAll" auf den Funktionsaufruf all() anstatt auf .value() reagiert.

Ansatz 1:

Beim Versuch, den gleichen Ansatz verwendet ich die Grafik/Gruppe konfiguriert ist, den Gesamtbeitrag zum Gesamtdurchschnitt für jeden Tag zu berechnen (In diesem Beispiel gibt es drei Spiele, in denen der Durchschnitt für den Tag für den Schläger für jeden Tag ist .500, aber wegen der unterschiedlichen Summen in den Schlägen und in den ABS, trägt jedes Spiel eine unterschiedliche Menge zum kumulativen Durchschnitt bei). Dies ist nicht erwünscht, weil ich möchte, dass die Grafik den tatsächlichen Durchschnitt für den ausgewählten Zeitraum anzeigt (Wenn ein Spiel ausgewählt ist, soll der Graph 0,500 anzeigen, das gleiche für zwei Spiele, das gleiche für alle drei seit dem kumulativen Durchschnitt für alle Mögliche Datumskombinationen sind .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(); 

Ansatz 2:

Nach einem Blick über Reductio Dokumentation dachte ich, ich könnte in der Lage sein, die .groupAll (groupingFunction) zu verwenden. Der Weg, das Problem teilweise zu lösen, besteht darin, die Funktion zu verwenden, um die Spiele von allen vorherigen Daten in die Berechnungen des aktuellen Datums aufzunehmen. Ich bin in der Lage, die richtige Anzahl von Treffern mit der .sum (d.h) -Funktion zu bekommen, aber ich kann derzeit die Anzahl nicht ändern, um die richtige Zahl zu sein (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()); 

Ansatz 3:

Ansatz 3 war zu versuchen, Funktionen erstellen individuelle reduzieren und füttern sie zu einem groupAll() reduzieren (reduceAdd, reduceRemove, reduceInitial) Funktion.. Dieser Versuch ergab zunächst keine graphische Darstellung. Nach dem Hinzufügen eines .valueAccessor (function (p) {return p.value.count> 0? P.value.total/p.value.count: 0}); Aufruf an das Ende der Funktion der Gesamtdurchschnitt wurde gezogen, aber nach dem Setzen von Haltepunkten habe ich entdeckt, dass die Funktion reduceRemove nie aufgerufen wurde, nachdem der Pinsel zum Filtern von Daten verschoben wurde.

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/

Jede Hilfe wäre sehr dankbar, und ich hoffe, dass dies mich über den Buckel bekommen könnte helfen und in der Lage sein, Probleme dieser Art auf eigene Faust zu lösen.

Antwort

1

Wenn Sie einen Durchschnitt mit Crossfilter berechnen, sollten Sie Crossfilter verwenden, um die Komponenten inkrementell zu berechnen und dann den Durchschnitt selbst zu berechnen, wenn es Zeit ist, die Daten anzuzeigen. Bei Verwendung von Reductio würden Sie dies tun, indem Sie eine Dummy-Dimension erstellen, die immer einen Wert enthält, und dann basierend auf dieser Dimension eine Gruppe erstellen, die die erforderlichen Komponenten berechnet. In Ihrem Beispiel:

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

Hier ist der Fiddle: https://jsfiddle.net/esjewett/qmtL6221/1/

Bitte beachte, dass ich nicht sicher bin, wenn Ihr an der Fledermaus Zahl bereits Spaziergänge oder nicht entfernt.Ich gehe davon aus, dass es Spaziergänge beinhaltet und entfernt sie, weil Spaziergänge in einer Batting-Durchschnittsberechnung nicht als Atbats gezählt werden, aber tue das nicht, wenn deine At-Bat-Zählung keine Spaziergänge beinhaltet.

P.S. Sah ein bisschen mehr und Ihr Ansatz 3 würde auch funktionieren. Problem ist, dass der Filter nicht auf Ihre Gruppe angewendet wird. Dies liegt daran, dass Sie Ihre Gruppe auf derselben Dimension dateDim definiert haben, nach der Sie filtern. Crossfilter wendet Filter nicht auf dieselbe Dimension an, für die der Filter definiert ist.