这是关于mac地址的数据。每分钟记录一次。对于每一分钟,我都有许多独特的Mac地址。
mac_add,created_time
18:59:36:12:23:33,2016-12-07 00:00:00.000
1c:e1:92:34:d7:46,2016-12-07 00:00:00.000
2c:f0:ee:86:bd:51,2016-12-07 00:00:00.000
5c:cf:7f:d3:2e:ce,2016-12-07 00:00:00.000
...
18:59:36:12:23:33,2016-12-07 00:01:00.000
1c:cd:e5:1e:99:78,2016-12-07 00:01:00.000
1c:e1:92:34:d7:46,2016-12-07 00:01:00.000
5c:cf:7f:22:01:df,2016-12-07 00:01:00.000
5c:cf:7f:d3:2e:ce,2016-12-07 00:01:00.000
...
我想使用dc.js和crossfilter创建2个条形图。请参考图表的图片。
第一个条形图很容易创建。这是可以推广的。我创建了“created_time”维度,并通过“mac_add”创建了一个group和reduceCount,如下所示:
var moveTime = ndx.dimension(function (d) {
return d.dd; //# this is the created_time
});
var timeGroup = moveTime.group().reduceCount(function (d) {
return d.mac_add;
});
var visitorChart = dc.barChart('#visitor-no-bar');
visitorChart.width(990)
.height(350)
.margins({ top: 0, right: 50, bottom: 20, left: 40 })
.dimension(moveTime)
.group(timeGroup)
.centerBar(true)
.gap(1)
.elasticY(true)
.x(d3.time.scale().domain([new Date(2016, 11, 7), new Date(2016, 11, 13)]))
.round(d3.time.minute.round)
.xUnits(d3.time.minute);
visitorChart.render();
问题出在第二个条形图上。这个想法是,一行数据等于1分钟,所以我可以聚合并总和每个mac地址的所有分钟,以获得每个mac地址的时间长度,通过“mac_add”创建另一个维度,并在“mac_add”上执行reduceCount “得到时间长度。然后目标是将时间长度分组30分钟。因此我们可以获得有多少时间长度为30分钟或更少的mac地址,有多少mac_add,时间长度在30分钟到1小时之间,有多少mac_add有时间长度在1小时到1.5小时之间等等...
如果我错了,请纠正我。从逻辑上讲,我认为第二个条形图的尺寸应该是时间长度组(例如< 30,< 1hr,< 1.5hr等)。但是时间长度组本身并没有修复。这取决于第一张图表的画笔选择。也许它只包含30分钟,也许它只包含1.5小时,也许它包含1.5小时和2小时等等......
所以我真的很困惑将哪些参数放入第二个条形图。以及获取所需参数的方法(如何对分组数据进行分组)。请帮我解释一下解决方案。
此致 马文
答案 0 :(得分:0)
我认为我们过去称之为“双重分组”,但我找不到以前的问题。
我从一个常规的crossfilter组开始,为mac地址,然后生成一个虚假组,按分钟数聚合。
var minutesPerMacDim = ndx.dimension(function(d) { return d.mac_add; }),
minutesPerMapGroup = minutesPerMacDim.group();
function bin_keys_by_value(group, bin_value) {
var _bins;
return {
all: function() {
var bins = {};
group.all().forEach(function(kv) {
var valk = bin_value(kv.value);
bins[valk] = bins[valk] || [];
bins[valk].push(kv.key);
});
_bins = bins;
// note: Object.keys returning numerical order here might not
// work everywhere, but I couldn't find a browser where it didn't
return Object.keys(bins).map(function(bin) {
return {key: bin, value: bins[bin].length};
})
},
bins: function() {
return _bins;
}
};
}
function bin_30_mins = function(v) {
return 30 * Math.ceil(v/30);
}
var macsPerMinuteCount = bin_keys_by_value(minutesPerMacGroup);
这将保留每个时间段的mac地址,我们稍后需要进行过滤。将非标准方法bins
添加到假组中的情况并不常见,但考虑到过滤界面只允许我们访问密钥,我无法想到保留该信息的有效方法。
由于该函数采用了分箱功能,如果我们想要更复杂的分箱,我们甚至可以使用threshold scale,而不是仅仅舍入到最接近的30分钟。 quantize scale是进行上述舍入的更通用方法。
使用此数据来驱动图表很简单:我们可以像往常一样使用维度和假组。
chart
.dimension(minutesPerMacDim)
.group(macsPerMinuteCount)
设置图表以便可以过滤它有点复杂:
chart.filterHandler(function(dimension, filters) {
if(filters.length === 0)
dimension.filter(null);
else {
var bins = chart.group().bins(); // retrieve cached bins
var macs = filters.map(function(key) { return bins[key]; })
macs = Array.prototype.concat.apply([], macs);
var macset = d3.set(macs);
dimension.filterFunction(function(key) {
return macset.has(key);
})
}
})
回想一下,我们正在使用一个键入mac地址的维度;这很好,因为我们想要过滤mac地址。但是图表正在接收其密钥的分钟计数,filters
将包含这些密钥,例如30
,60
,90
等。所以我们需要提供一个filterHandler,它采用分钟计数键并根据这些键过滤维度。
注意1:这都是未经测试的,所以如果它不起作用,请将一个例子作为小提琴或bl.ock发布 - 有小提琴和块可以分叉开始on the main page。
注2:严格来说,这不是衡量连接的长度:它是计算连接的总分钟数。不确定这对你来说是否重要。如果用户断开连接然后在时间范围内重新连接,则两个会话将计为一个。我认为你必须预处理以获得持续时间。
编辑:基于你的小提琴(谢谢!),上面的代码确实有效。这只是设置x比例和xUnits
正确的问题。
chart2
.x(d3.scale.linear().domain([60,1440]))
.xUnits(function(start, end) {
return (end-start)/30;
})
线性刻度在这里会很好 - 我不会尝试量化那个刻度,因为已经设置了30分钟的刻度。我们确实需要设置xUnits
,以便dc.js知道制作条形图的宽度。
我不确定为什么elasticX
在这里不起作用,但<30
bin完全使其他所有内容相形见绌,所以我认为最好不要这样做。