2015-12-28 3 views
0

Я пытаюсь создать переменную для ввода dc.js с помощью пользовательской редукции (reduceAdd, reduceRemove и т. Д.), И мне трудно понять, как ее кодировать.Как сделать сложную кроссфильтрную ошибку

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

Logic: Для каждого уникального contact_week доступны (даты), найти максимальное значение week_number, затем суммировать переменную TOTCOUNT и переменную DECAY_CNT и вычислить процент (DECAY_CNT/TOTCOUNT) ,

Вот исходный код без использования crossfilter:

//Decay % logic 
    var dates = d3.map(filter1,function(d) { return d.CONTACT_WEEK;}).keys() ; 
    console.log(dates); 
    var sum1,sum2 = 0; 


    for(var i=0; i<dates.length; i++) 
    { 
     data1 = filter1.filter(function(d) { return d.CONTACT_WEEK == dates[i] ;}); 
     //console.log(data1); 
     var max = d3.max(data1, function(d) { return +d.WEEK_NUMBER ;}); 
     //console.log(max); 
     data2 = data1.filter(function(d) { return d.WEEK_NUMBER == max ;}); 

     var sum1 = d3.sum(data2, function(d) { return d.TOTCOUNT ;}); 
     var sum2 = d3.sum(data2, function(d) { return d.DECAY_CNT ;}); 
     console.log(sum1); 
     var decay = sum2/sum1 * 100 ; 
     console.log(decay); 

    } 

Первый шаг в этом заключается в определении уникальных значений дат (contact_week) - Как идти об этом в функции снижения, как это уже цикл for, проходящий через данные?

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

Любая помощь в подходе/решения будут высоко оценили.

UPDATE2:

Попытка новый подход с использованием reductio js

объяснение данных:

Несколько столбцов в моих данных - contact_week (даты); week_number (числа от -4 до 6); decay_cnt (целые числа); totcount (целые числа); продолжительность (порядковые значения - pre, во время и после);

Теперь, мне нужно, чтобы вычислить процент, называемый распад%, который рассчитывается следующим образом: Для каждого уникального contact_week, найти максимум из week_number, теперь для этого фильтрованного набора данных, вычислить сумму (decay_cnt)/сумма (totcount)

Это должен быть построен в BarChart, где ось х является длительность и метрика - распад% является ось у

в погоне расчета макс будним числа индивидуальных дат, Я построили график гистограмм на данный момент, с contact_week как осью x и максимальным числом__схемы в качестве оси y. Как мне получить диаграмму, которая мне нужна?

Код:

dateDimension2 = ndx.dimension(function(d) {return d.CONTACT_WEEK ;}); 
decayGroup = reductio().max(function (d) { return d.WEEK_NUMBER; })(dateDimension2.group()); 


chart2 
    .width(500) 
    .height(200) 
    .x(d3.scale.ordinal()) 
    //.x(d3.scale.ordinal().domain(["DURING","POST1"])) 
    .xUnits(dc.units.ordinal) 
    //.xUnits(function(){return 10;}) 
    //.brushOn(false) 
    .yAxisLabel("Decay (in %)") 
    .dimension(dateDimension) 
    .group(decayGroup) 
    .gap(10) 
    .elasticY(true) 
    //.yAxis().tickValues([0, 5, 10, 15]) 
    //.title(function(d) { return d.key + ": " + d3.round(d.value.new_count,2); }) 
    /*.valueAccessor(function (p) { 
    //return p.value.count > 0 ? (p.value.dec_total/p.value.new_count) * 100 : 0; 
    return p.value.decay ; 
    })*/ 
    .valueAccessor(function(d) { return d.value.max; }) 
    .on('renderlet', function(chart) { 
     chart.selectAll('rect').on("click", function(d) { 
      console.log("click!", d); 
     }); 
    }) 
    .yAxis().ticks(5); 

Любой подход/предложения будут высоко оценены

Я думаю, что решение в основном заключается в поддельные группы/размеры и УМЕНЬШЕНИЕ комбинированный подход расслоение плотной. Любые альтернативы приветствуются!

+1

Пожалуйста, покажите код/​​reduceRemove reduceAdd, который вызывает ошибку. Лучше всего было бы создать рабочий пример проблемы на jsfiddle или аналогичном сайте. –

+0

Хорошей новостью является основной цикл, и первый фильтр должен обрабатываться группами crossfilter автоматически. Плохая новость заключается в том, что в crossfilter нет встроенного в min/max типа, и их сложно сделать эффективно. Вы в конечном итоге сохраняете некоторую ссылку на строки в каждом ящике. Если вы будете искать вокруг, вы найдете различные коды для этого, например. http://stackoverflow.com/a/32925852/676195 - IIUC Ваша проблема - это просто более сложное сокращение данных того же типа. – Gordon

+0

[reductio] (https://github.com/esjewett/reductio) также имеет материал min/max, но я не знаю, поддерживает ли он фильтрацию строк в корзине и уменьшает их. Интересная задача дизайна, @ Этан! – Gordon

ответ

3

Я только что добавил a FAQ и an example для решения этой проблемы.

Как объясняется здесь, идея состоит в том, чтобы поддерживать массив строк, которые попадают в каждый бит, начиная с crossfilter doesn't provide access to that yet.Как только мы получим фактические строки, ваши вычисления почти такие же, как вы сейчас, за исключением того, что crossfilter отслеживает список недель для вас.

Таким образом, вы можете использовать эти функции из примера:

function groupArrayAdd(keyfn) { 
     var bisect = d3.bisector(keyfn); 
     return function(elements, item) { 
      var pos = bisect.right(elements, keyfn(item)); 
      elements.splice(pos, 0, item); 
      return elements; 
     }; 
    } 

    function groupArrayRemove(keyfn) { 
     var bisect = d3.bisector(keyfn); 
     return function(elements, item) { 
      var pos = bisect.left(elements, keyfn(item)); 
      if(keyfn(elements[pos])===keyfn(item)) 
       elements.splice(pos, 1); 
      return elements; 
     }; 
    } 

    function groupArrayInit() { 
     return []; 
    } 

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

Определите размер недели и группы следующим образом:

var weekDimension = ndx.dimension(function(d) {return d.CONTACT_WEEK ;}), 
    id_function = function(r) { return r.ID; }, 
    weekGroup = weekDimension.group().reduce(groupArrayAdd(id_function), groupArrayRemove(id_function), groupArrayInit); 

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

(Конечно, этот код не тестировался, потому что я не знаю ваших данных.)

var calculateDecay = function(kv) { 
    // kv.value has the array produced by the reduce functions. 
    var data1 = kv.value; 
    var max = d3.max(data1, function(d) { return +d.WEEK_NUMBER ;}); 
    data2 = data1.filter(function(d) { return d.WEEK_NUMBER == max ;}); 

    var sum1 = d3.sum(data2, function(d) { return d.TOTCOUNT ;}); 
    var sum2 = d3.sum(data2, function(d) { return d.DECAY_CNT ;}); 

    var decay = sum2/sum1 * 100 ; 
    return decay; 
} 

chart.valueAccessor(calculateDecay); 
+0

Это здорово, он работает с правильными значениями в конце концов! Прежде всего, спасибо за все усилия и огромную помощь здесь! Однако в моем вопросе оставлено одно простое (или сложное) оговорку, я хочу, чтобы измерение было DURATION (not contact_week). Ось X должна показывать длительность по порядку. (Я просто тестировал с помощью contact_week раньше). Данные объясняются выше в однострочном выражении, продолжительность - это всего лишь еще один столбец (значения - во время, pre, post и т. Д.). Это возможно? Я пробовал изменять имена измерений, что не помогает, поскольку оно связано с группой. Пожалуйста, дайте мне знать, как это сделать –

+0

Я не вижу, как это влияет на основной вопрос. Не можете ли вы просто определить свое измерение соответственно и использовать те же функции сокращения, которые я описал? – Gordon

+0

О, мой плохой! Я пытался что-то еще. Он отлично работает, и вы решили вопрос! Большое спасибо, Гордон! –

Смежные вопросы