2015-12-29 2 views
2

Я не могу составить правильный график, показывающий группу данных по неделям (и в разные годы).Размеры dc.js/crossfilter (год/неделя)

псевдо SQL даст:

select sum ('task') 
group by 'year', 'week' (and maybe later 'site') 

Мои данные выглядят более или менее, как это:

{ "date" : "20150427", "week" : 18, "site" : "a" "task" : 3, } 
{ "date" : "20150427", "week" : 18, "site" : "b" "task" : 4, } 
{ "date" : "20150427", "week" : 18, "site" : "c" "task" : 2, } 
{ "date" : "20150427", "week" : 18, "site" : "d" "task" : 3, } 
{ "date" : "20150428", "week" : 18, "site" : "a" "task" : 3, } 
{ "date" : "20150428", "week" : 18, "site" : "b" "task" : 3, } 
{ "date" : "20150429", "week" : 18, "site" : "c" "task" : 2, } 
{ "date" : "20150429", "week" : 18, "site" : "d" "task" : 3, } 
{ "date" : "20140512", "week" : 20, "site" : "d" "task" : 6, } 
{ "date" : "20140512", "week" : 20, "site" : "a" "task" : 6, } 
{ "date" : "20140513", "week" : 20, "site" : "b" "task" : 4, } 
{ "date" : "20140513", "week" : 20, "site" : "c" "task" : 1, } 
{ "date" : "20140519", "week" : 21, "site" : "b" "task" : 2, } 
{ "date" : "20140519", "week" : 21, "site" : "c" "task" : 1, } 
{ "date" : "20140519", "week" : 21, "site" : "d" "task" : 3, } 
{ "date" : "20140519", "week" : 21, "site" : "a" "task" : 1, } 
{ "date" : "20140520", "week" : 21, "site" : "b" "task" : 2, } 
{ "date" : "20140520", "week" : 21, "site" : "c" "task" : 3, } 
{ "date" : "20140520", "week" : 21, "site" : "d" "task" : 1, } 
{ "date" : "20140520", "week" : 21, "site" : "a" "task" : 1, } 

Это пример моих данных, он может иметь разные годы, сайты или задачи

Я пробовал это, и он не работает, потому что barChart кумулирует неделю всех лет:

d3.json("/graph", function(dataJson) { 


var dataTable = dc.dataTable("#dc-table-graph"); 
var barChart = dc.barChart("#chart-bar-ordersperweek"); 

var data = dataJson; 
var dateFormat = d3.time.format("%Y%m%d"); 
data.forEach(function (d) { d.date = dateFormat.parse(d.date); }); 


//dimension 
var dateDim = ndx.dimension(function (d) { return d.date; }); 
var weekDim = ndx.dimension(function(d) {return d.week;}); 

//group 
var orderByWD = weekDim.group().reduceSum(function (d) { return d.task; }); 


barChart 
    .width(1000).height(250) 
    .dimension(weekDim) 
    .group(orderByWD) 
    .x(d3.scale.ordinal().domain(d3.range(minWeek.week-1,maxWeek.week+1))) 
    .xUnits(dc.units.ordinal) 
    .y(d3.scale.linear().domain([0, 6000])) 
    .margins({top: 20, right: 30, bottom: 50, left: 80}) 
    .label(function(d) { return d.value}) 
    ; 


dataTable.width(800).height(800) 
     .dimension(dateDim)  
     .group(function (d) { return 'Week ' + d.week}) 
     .size(5000) 
     .columns([ 
      function (d) { var format = d3.format('02d'); 
       return d.date.getFullYear() +'/'+ format(d.date.getMonth()+1) + '/' + format(d.date.getDate()); }, 
      function (d) { return d.week; }, 
      function (d) { return d.site; }, 
      function (d) { return d.task; } 
     ]) 
     .sortBy(function (d) { return Number(d.date) + d.task; }) 
     .order(d3.descending); 

     dataTable.on('renderlet', function(chart){ 
      chart.selectAll('.dc-table-group').classed('info',true); 
     }); 

dc.renderAll(); 

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

В dataTable как я могу суммировать задачу по сайту, сгруппированным по неделям?

Спасибо за любую помощь

EDIT я есть добавить jsfiddle https://jsfiddle.net/d4qsd8wh/

+0

Я думаю, что dataTable работает на основе измерения, а не группы, поэтому вам, вероятно, потребуется создать поддельное измерение, которое возвращает записи, которые вы хотите отобразить. Если вы соберете рабочий пример с помощью jsfiddle или чего-то подобного, я или кто-то еще здесь, возможно, заставит его работать на вас. –

+0

Я просто добавлю это https://jsfiddle.net/d4qsd8wh/ – okuteur

ответ

0

D3 имеет некоторые довольно мощные инструменты, которые помогут вам сформировать свои данные. Это просто пример. Сделав ключ года + Неделя мы можем подвести задачи

var out = d3.nest() 
    .key(function(d) { return d.date.substring(0,4)+d.week; }) 
    .rollup(function(v) { return { 
     date: v[0].date, 
     task: d3.sum(v, function(d) { return d.task; }) 
    }; 
    }) 
    .entries(data); 

Это сделает out массив из объектов, выглядит следующим образом.

[ 
    { 
    "key": "201420", 
    "values": { 
     "date": "20140512", 
     "task": 17 
    } 
    }, 
    { 
    "key": "201421", 
    "values": { 
     "date": "20140519", 
     "task": 14 
    } 
    }, 
    { 
    "key": "201518", 
    "values": { 
     "date": "20150427", 
     "task": 23 
    } 
    } 
] 

Поскольку вы группируя по неделям, то дата в основном произвольно, так что я только что это показывает первый в списке сгруппированных даты. Вы также можете добавить еще один .key(function(d) { return d.site; } под первым .key в подгруппу по сайту.

1

Итак, что вам нужно сделать, это создать поддельное «измерение» для dataTable. В текущем подходе вы можете сделать это следующим образом:

// Actually a dimension keyed on week and site 
var fakeDateDim = { 
    top: function(d) { 
    var m = dc.d3.map(); 
    dateDim.top(Infinity).forEach(function(g) { 
     if(m.has(g.week + g.site)) { 
     m.get(g.week + g.site).task += g.task 
     } else { 
     // Create the "record" 
     m.set(g.week + g.site, { 
      week: g.week, 
      site: g.site, 
      task: g.task 
     }) 
     } 
    }) 

    return m.values(); 
    } 
} 

Тогда в DataTable, использовать что fakeDateDim в месте вашего текущего dateDim. (Кроме того, вы должны удалить столбцы таблицы даты и недели.)

Вот рабочий пример на примере вы положили вместе: https://jsfiddle.net/s2c9rhxw/

Обратите внимание, что вы можете использовать d3.nest, как указано в ответ by @ ian-h, но он маскирует некоторые из того, что вы делаете, поэтому я думаю, что, вероятно, лучше использовать конструкции нижнего уровня, такие как Map или d3.map, до тех пор, пока вы не будете довольны вычислением. Независимо от того, как вы фактически выполняете расчет, ключ состоит в том, чтобы обернуть его в поддельный объект измерения, который dc.js сможет использовать.

+0

, которые решают другую часть моей проблемы. – okuteur

1

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

Другими словами, я расцениваю это как сердце вашего вопроса:

Я попробовал это, и это не работает, потому что BarChart кумулатов неделю всех лет

Что ISN На самом деле о dataTable, но barChart.

Чтобы ответить на этот вопрос: да, я думаю, что ваше поле week бесполезно. Вместо этого используйте анализируемые даты и d3.time.week БИН за неделю:

var weekDim = ndx.dimension(function(d) {return d3.time.week(d.date);}); 

Затем установите график бар использовать даты единиц вместо порядковых:

barChart 
    ... 
    .x(d3.time.scale()) 
    .xUnits(d3.time.weeks) 
    .elasticX(true) // or calculate minWeek/maxWeek using date objects 

Что d3.time.week делает, как и другие d3 time interval functions, является вернуть дату, которая находится в начале интервала. (Так как d3.time.week является синонимом для d3.time.sunday, он возвращается в полночь в воскресенье перед каждой датой - используйте d3.time.monday, если вы хотите использовать понедельники в неделях вместо этого.) Обрезание каждой даты до начала ее интервала - это хороший способ забить даты, не забывая год, в который они входят.

Далее d3.time.weeks (уведомление s) - связанная функция, которая может подсчитывать количество интервалов (недель) в пределах любого временного диапазона. dc.js нужна функция подсчета xUnits, чтобы определить количество отображаемых баров.

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

+0

Я думаю, что может быть несколько вопросов. Может быть, мы можем собрать омнибусный ответ :-) –

+0

ОК, которые решают часть моей проблемы :) но как я могу определить «понедельник» как начало недели (в настоящее время воскресенье - первый день)? _is this part d3.time.week (d.date) _ благодарю вас за помощь. Gordon – okuteur

+0

Отлично, я надеюсь, что некоторые из других ответов также помогут! [d3.time.week] (https://github.com/mbostock/d3/wiki/Time-Intervals#week) является просто синонимом 'd3.time.sunday', поэтому вы можете использовать' d3. time.monday', чтобы получить то, что вы хотите. Я уточню, что это делает выше. – Gordon

0

Вам нужно создать свой weekDim следующим образом:

var weekDim = ndx.dimension(function(d) { 
    return d.date.substring(0,4) + "" + d.week; 
}); 

, а затем создать группу по этому измерению следующим образом:

function reduceAdd(p, v) { 
    return p + v.task; 
} 

function reduceRemove(p, v) { 
    return p - v.task; 
} 

function reduceInitial() { 
    return 0; 
} 
var m = weekDim.group().reduce(reduceAdd,reduceRemove,reduceInitial); 

и вы получите результат, как m.top (бесконечность). Я не знаю, как вы можете использовать этот dataTable, но вывод выше будет именно тем, что вы хотите. Надеюсь, это поможет

+0

Извините, но я не думаю, что это полезно. Это сокращение эквивалентно 'reduceSum' в вопросе, и d3 имеет лучшие способы борьбы со временем. Благодарим за вклад! – Gordon