2016-04-27 4 views
1

У меня проблема, аналогичная той, что описана в DC.JS get last month value as filter.Трек и фильтр в прошлом месяце в dc.js

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

Для этого мне нужно отслеживать последний месяц, выбранный путем чистки линейной диаграммы. Смотрите мой jsFiddle здесь: https://jsfiddle.net/BernG/wo60z64j/12/

var data = [{date:"201501",company:"A", product: "Prod1", stock:575} 
    , {date:"201502",company:"A", product: "Prod1", stock:325} 
    , {date:"201503",company:"A", product: "Prod1", stock:200} 
    , {date:"201504",company:"A", product: "Prod1", stock:450} 
    , {date:"201501",company:"A", product: "Prod2", stock:279} 
    , {date:"201502",company:"A", product: "Prod2", stock:93} 
    , {date:"201503",company:"A", product: "Prod2", stock:0} 
    , {date:"201504",company:"A", product: "Prod2", stock:372}  
    , {date:"201501",company:"A", product: "Prod3", stock:510} 
    , {date:"201502",company:"A", product: "Prod3", stock:340} 
    , {date:"201503",company:"A", product: "Prod3", stock:680} 
    , {date:"201504",company:"A", product: "Prod3", stock:170}  
    , {date:"201501",company:"B",product: "Prod1", stock:1000} 
    , {date:"201502",company:"B",product: "Prod1", stock:1100} 
    , {date:"201503",company:"B",product: "Prod1", stock:900} 
    , {date:"201504",company:"B",product: "Prod1", stock:1200} 
    , {date:"201501",company:"B",product: "Prod2", stock:1000} 
    , {date:"201502",company:"B",product: "Prod2", stock:1200} 
    , {date:"201503",company:"B",product: "Prod2", stock:900} 
    , {date:"201504",company:"B",product: "Prod2", stock:1200}   
    , {date:"201501",company:"B",product: "Prod3", stock:1000} 
    , {date:"201502",company:"B",product: "Prod3", stock:1100} 
    , {date:"201503",company:"B",product: "Prod3", stock:900} 
    , {date:"201504",company:"B",product: "Prod3", stock:600}]; 


// Reading and formatting values 
var dateFormat = d3.time.format('%Y%m'); 
data.forEach(function (d) { 
    d.dd = dateFormat.parse(d.date); 
    d.year = d3.time.year(d.dd); 
    d.month = d3.time.month(d.dd); 
}); 

// Definition of crossfilter and dimensions 
var  ndx = crossfilter(data) 
    , dimMonth = ndx.dimension(function(d){return d.month}) 
    , dimProduct = ndx.dimension(function(d){return d.product}) 
    , dimCompany = ndx.dimension(function(d){return d.company;}); 


var  lastStaticDate = dimMonth.top(1)[0].month;  // identify last date in full time domain 
var  firstStaticDate = dimMonth.bottom(1)[0].month; // identify first date in full time domain 


// Definition of a function to keep track of the last date value in the brush attached to the chartMonth. 
// If chartMonth object does not exist or its corresponding brush is empty (has not been brushed), then it returns the lastStaticDate 
// otherwise, it returns the last date in the brush selection 
var getLastDate = function(){ 
        if (typeof chartMonth === "undefined"){ // test if chartMonth is already in the DOM, if not return lastStaticDate 
         return lastStaticDate; 
         } 
        else { 
         if (chartMonth.brush().empty()) { // if chartMonth has been created but brush does not have have a selection 
          return lastStaticDate; 
          } 
         else { 
          return chartMonth.brush().extent()[1]; 
          }; 
         } 
        }; 

var lastDate = d3.time.month.ceil(getLastDate()); // lastDate is snapped to return a date where we have data in the x-domain 


dateBal.innerHTML = lastDate;  


var  grpMonth = dimMonth.group().reduceSum(function(d){return d.stock;}); // the line chart displays all values in the x-axis to show stock evolution 

// Definition of custom reduce functions      
function reduceAdd(p,v) { 
    if (p.month===lastDate){         
     p.stock += v.stock; 
     return p; 
     } 
    else {return p;} 
}; 

function reduceRemove(p,v) { 
    if (p.month!== lastDate){        
     p.stock -= v.stock; 
     return p;} 
    else {return p;} 
}; 

function reduceInitial() { 
    return {stock: 0} 
}; 

// Application of reduce functions 

var  grpCompany = dimCompany 
        .group() 
        .reduce(reduceAdd, reduceRemove, reduceInitial); 

var  grpProduct = dimProduct 
        .group() 
        .reduce(reduceAdd, reduceRemove, reduceInitial); 


var chartCompany = dc.barChart('#chartCompany'); 
var chartProduct = dc.barChart("#chartProduct"); 
var chartMonth = dc.lineChart('#chartMonth'); 

chartCompany 
    .width(400) 
    .height(400) 
    .margins({top: 50, right: 50, bottom: 50, left: 50}) 
    .dimension(dimCompany) 
    .group(grpCompany) 
    .x(d3.scale.ordinal()) 
    .xUnits(dc.units.ordinal) 
    .elasticY(true); 

chartProduct 
    .width(400) 
    .height(400) 
    .margins({top: 50, right: 50, bottom: 50, left: 50}) 
    .dimension(dimProduct) 
    .group(grpProduct) 
    .x(d3.scale.ordinal()) 
    .xUnits(dc.units.ordinal) 
    .elasticY(true); 


chartMonth 
    .width(400) 
    .height(400) 
    .margins({top: 50, right: 50, bottom: 50, left: 50}) 
    .renderlet(function (chart) { 
     // rotate x-axis labels 
     chart.selectAll('g.x text') 
     .attr('transform', 'translate(-10,10) rotate(315)'); 
     }) 
    .dimension(dimMonth) 
    .group(grpMonth) 
    .x(d3.time.scale().domain([firstStaticDate, lastStaticDate])) 
    .xUnits(d3.time.months) 
    .elasticX(true); 

dc.renderAll(); 

Решение, которое я попытался на основе только ответ на поставленный выше вопрос (который, кстати, не был отмечен, как принято) и следовать этой логике:

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

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

Мои конкретные вопросы:

  • Как я могу сделать переменную (lastDate) реактивная? В консоли хорошо работает следующее: d3.time.month.ceil (getLastDate()). Однако он не реагирует на интерактивное событие чистки.

  • Какие изменения необходимо внести в моих пользовательских функциях сокращения, чтобы накапливать только значения, соответствующие последнему дате и исключая все остальные? По какой-то причине клиент сокращает функции, поскольку они в настоящее время определены, не аккумулировать значения запасов правильно. Например, при инициализации, если я осмотреть объект, где grpCompany проживает, он показывает стоимость акций как 0. grpCompany.all() in console

    Наконец, прежде чем голосовать, чтобы пометить этот вопрос как дубликат пожалуйста, учтите следующее:

  • Оригинальный пост, похоже, не имеет принятого ответа.
  • Было предложение помочь, если OP предоставил рабочий jsFiddle, но ни один из них не был предоставлен.
  • Я хотел сделать следующий комментарий в оригинальном посте, прося уточнить, но это было невозможно сделать, потому что у меня еще нет необходимой репутации, чтобы опубликовать комментарий.

ответ

0

Хорошо, это действительно сложно, поэтому я начал свой комментарий к предыдущему вопросу, сказав, что Crossfilter не очень хорош в этом. Мой ответ был довольно сложным, и вы не смогли сделать то, что я хотел предложить, но это не ваша вина. Библиотека Universe поддерживает некоторые из ваших предложений, но в целом я бы рекомендовал переосмыслить ваш подход, если это усложняется. Тем не менее, ваш сценарий, как указано, также немного отличается от приведенного в предыдущем вопросе и имеет более простой ответ:

В вашем случае, что вы на самом деле должны делать, это использовать пользовательский DC.JS filterFunction сделать запас график изменения баланса фильтр только к последней дате в кисти:

chartMonth 
    ... 
    .filterHandler(function(d,f) { 
    if(f.length > 0) { 
     d.filterExact(d3.time.month.ceil(f[0][1])); 
     dateBal.innerHTML = d3.time.month.ceil(f[0][1]); 
    } else { 
     d.filterAll(); 
     dateBal.innerHTML = "No month selected" 
    } 
    return f; 
    }) 

Вот рабочая версия, основанная на вашем JSFiddle: https://jsfiddle.net/esjewett/utohm7mq/2/

Итак, это простой ответ. Фактически это просто фильтрует весь ваш Crossfilter до последнего месяца, выбранного в кисти (или фактически в следующем месяце). Если вы также хотите отфильтровать некоторые другие графики до фактических дат, выбранных кистью, то вы говорите о наличии нескольких конфликтующих фильтров, и Crossfilter в настоящее время не очень хорошо это поддерживает. Мы заинтересованы в добавлении функциональных возможностей для поддержки нескольких групп фильтров, но пока не начали заниматься этим. В этом случае лучший подход сейчас, вероятно, состоит в том, чтобы поддерживать 2 отдельных Crossfilters и управлять различными группами графиков с разных Crossfilters.

+1

Благодарим вас за быстрый ответ. Решение, безусловно, очень простое и работает отлично. Я просто сделал небольшое изменение в filterHandler, чтобы включить условие, где f.length == 0, поэтому я могу применить фильтр с lastStaticDate. Это позволяет отображать столбчатые диаграммы на уже загруженной загрузке страницы на основе последней даты в линейной диаграмме. – BGutierrez

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