尝试使用样本数据中3列的最小值,最大值和平均值创建d3/dc/xfilter dataTable.一直在苦苦挣扎但无法理解如何将reduceAdd,reduceRemove,reduceInitial函数集成到dataTable中以创建三个必要的行.
期望的输出将如下所示:
------------------------------------------
| Value | Cars | Bikes | Trucks |
------------------------------------------
| Min | 125 | 310 | 189 |
------------------------------------------
| Max | 230 | 445 | 290 |
------------------------------------------
| Avg | 178 | 385 | 245 |
------------------------------------------
Run Code Online (Sandbox Code Playgroud)
也看不出如何添加第一个(标签)列.我知道reduceInitial可以返回一个数组(例如['min', 'max', 'avg']
)但是如何引用它的标签?
var myCSV = [
{"shift":"1","date":"01/01/2016/08/00/00","car":"178","truck":"255","bike":"317","moto":"237"},
{"shift":"2","date":"01/01/2016/17/00/00","car":"125","truck":"189","bike":"445","moto":"273"},
{"shift":"3","date":"02/01/2016/08/00/00","car":"140","truck":"219","bike":"328","moto":"412"},
{"shift":"4","date":"02/01/2016/17/00/00","car":"222","truck":"290","bike":"432","moto":"378"},
{"shift":"5","date":"03/01/2016/08/00/00","car":"200","truck":"250","bike":"420","moto":"319"},
{"shift":"6","date":"03/01/2016/17/00/00","car":"230","truck":"220","bike":"310","moto":"413"},
{"shift":"7","date":"04/01/2016/08/00/00","car":"155","truck":"177","bike":"377","moto":"180"},
{"shift":"8","date":"04/01/2016/17/00/00","car":"179","truck":"203","bike":"405","moto":"222"},
{"shift":"9","date":"05/01/2016/08/00/00","car":"208","truck":"185","bike":"360","moto":"195"},
{"shift":"10","date":"05/01/2016/17/00/00","car":"150","truck":"290","bike":"315","moto":"280"},
{"shift":"11","date":"06/01/2016/08/00/00","car":"200","truck":"220","bike":"350","moto":"205"},
{"shift":"12","date":"06/01/2016/17/00/00","car":"230","truck":"170","bike":"390","moto":"400"},
];
dataTable = dc.dataTable('#dataTable');
lc1 = dc.lineChart("#line1");
lc2 = dc.lineChart("#line2");
lc3 = dc.lineChart("#line3");
var dateFormat = d3.time.format("%d/%m/%Y/%H/%M/%S");
myCSV.forEach(function (d) {
d.date = dateFormat.parse(d.date);
});
myCSV.forEach(function (d) {
d['car'] = +d['car'];
d['bike'] = +d['bike'];
d['moto'] = +d['moto'];
});
//console.log(myCSV);
var facts = crossfilter(myCSV);
var dateDim = facts.dimension(function (d) {return d.date});
var carDim = facts.dimension(function (d) {return d['car']});
var dgCar = dateDim.group().reduceSum(function (d) {return d['car']});
var bikeDim = facts.dimension(function (d) {return d['bike']});
var dgBike = dateDim.group().reduceSum(function (d) {return d['bike']});
var motoDim = facts.dimension(function (d) {return d['moto']});
var dgMoto = dateDim.group().reduceSum(function (d) {return d['moto']});
var minDate = new Date ("2016-01-01T08:00:00.000Z");
var maxDate = new Date ("2016-01-03T17:00:00.000Z");
var maxY = d3.max(myCSV, function(d) {return d['car']});
function reduceAdd(i,d){ return i+1; }
function reduceRemove(i,d){return i-1; }
function reduceInitial(){ return ['min','max','avg'];}
dataTable
.width(jsTablWidth)
.height(400)
.dimension(dateDim)
.group( function(d){return '';} )
.columns([
{
label: 'Value',
format: function(d) { return dateGroup1.reduce(reduceAdd,reduceRemove,reduceInital); }
},
{
label: tSel1.replace(/_/g, " "),
format: function(d) { return //avg cars ; }
},
{
label: tSel2.replace(/_/g, " "),
format: function(d) { return //avg bikes ; }
},
{
label: tSel3.replace(/_/g, " "),
format: function(d) { return //avg moto; }
}
]);
dc.renderAll();
dc.redrawAll();
Run Code Online (Sandbox Code Playgroud)
svg{height:280px;}
Run Code Online (Sandbox Code Playgroud)
<script src="http://cdnjs.cloudflare.com/ajax/libs/d3/3.3.3/d3.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.1/crossfilter.min.js"></script>
<script src="http://dc-js.github.io/dc.js/js/dc.js"></script>
<link href="http://dc-js.github.io/dc.js/css/dc.css" rel="stylesheet"/>
<svg id="dataTable"></svg>
<svg id="line1"></svg>
<svg id="line2"></svg>
<svg id="line3"></svg>
Run Code Online (Sandbox Code Playgroud)
好的,希望您可以将桌子对角线对换,将运输方式设置为行而不是列。如果不弄清楚那部分,这个解决方案已经很古怪了。
除了跟踪所有值之外,实际上没有其他方法可以计算出最小值和最大值。因此,我们将使用复杂缩减示例中的缩减。这些实际上根本不会减少,但会维护已过滤行的排序数组。
我们需要一个唯一键来保留排序后的数组(以便我们删除正确的行。幸运的是,您在shift
字段中有该键。
因此,这里是那些功能,或者更确切地说是在给定唯一键访问器的情况下生成缩减器的功能。
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 [];
}
Run Code Online (Sandbox Code Playgroud)
由于这些保留对整个行的引用,因此我们只需要一组即可。我们在计算以下指标时将使用更具体的访问器。
在这里,我们需要crossfilter.groupAll,它将所有内容减少到一个bin中。这是因为行没有被任何键分区。每行都有助于所有运输方式:
var filteredRows = facts.groupAll().reduce(
groupArrayAdd(dc.pluck('shift')),
groupArrayRemove(dc.pluck('shift')),
groupArrayInit
);
Run Code Online (Sandbox Code Playgroud)
现在是最荒谬的部分。我们将创建您见过的最假的尺寸对象。重要的是,它是具有.bottom()
动态计算每一行方法的对象:
var fakeDim = {
bottom: function() {
return [
{key: 'Car', value: filteredRows.value(), acc: dc.pluck('car')},
{key: 'Truck', value: filteredRows.value(), acc: dc.pluck('car')},
{key: 'Bike', value: filteredRows.value(), acc: dc.pluck('bike')},
{key: 'Moto', value: filteredRows.value(), acc: dc.pluck('moto')}
];
}
};
Run Code Online (Sandbox Code Playgroud)
除了,等等,看起来根本没有做任何计算,只是在获取值吗?那有什么奇怪的acc
?
好吧,我们正在准确地生成生成表行所需的源数据,并且我们将使用format
下面的访问器实际计算所有内容。我们将key
“”用作“标签列”,将原始行保留在value
成员中;并且我们将提供acc
用于计算指标的访问器。
数据表定义如下所示:
dataTable
.width(400)
.height(400)
.dimension(fakeDim)
.group( function(d){return '';} )
.columns([
{
label: 'Value',
format: function(d) {
return d.key;
}
},
{
label: 'Min',
format: function(d) {
return d3.min(d.value, d.acc);
}
},
{
label: 'Max',
format: function(d) {
return d3.max(d.value, d.acc);
}
},
{
label: 'Avg',
format: function(d) {
return d3.mean(d.value, d.acc);
}
}
]);
Run Code Online (Sandbox Code Playgroud)
这是所有指标最终计算出来的地方。我们将提供所有可用的行,并且每个表行都有一个访问器。d3数组具有方便的功能,可用于计算数组的最小值,最大值和平均值。繁荣,完成。
我把一个堆积的图表放到这个小提琴中进行测试。(我知道堆叠这些值可能没有任何意义,这只会有助于进行过滤。)
http://jsfiddle.net/gordonwoodhull/g4xqvgvL/21/
对此的额外奖励使我想起了我从来没有解决过表转换问题,所以我想看看一下,因为它很有趣。我仍然认为赏金应该归@SergGr,但这是根据类别,维和列访问器/格式器转置表的解决方案。
首先,我们需要类别列表,因此让我们更好地组织类别和字段名称:
var categories = {
Car: 'car',
Truck: 'truck',
Bike: 'bike',
Moto: 'moto'
};
Run Code Online (Sandbox Code Playgroud)
现在可以简化伪维,因为它是从以下类别映射生成的:
function fake_dimension(cats) {
return {
bottom: function() {
return Object.keys(cats).map(function(k) {
return {
key: k,
value: filteredRows.value(),
acc: dc.pluck(cats[k])
};
});
}
};
}
var fakeDim = fake_dimension(categories);
Run Code Online (Sandbox Code Playgroud)
我们需要将列定义从图表定义中拉出,因为我们将对其进行转换:
var columns = [
{
label: 'Value',
format: function(d) {
return d.key;
}
},
{
label: 'Min',
format: function(d) {
return d3.min(d.value, d.acc);
}
},
{
label: 'Max',
format: function(d) {
return d3.max(d.value, d.acc);
}
},
{
label: 'Avg',
format: function(d) {
return d3.mean(d.value, d.acc);
}
}
];
Run Code Online (Sandbox Code Playgroud)
最后,我们可以编写转置函数:
function transpose_datatable(cats, dim, cols) {
var cols2 = d3.map(cols, function(col) { // 1
return col.label;
});
return {
dim: { // 2
bottom: function() {
var dall = d3.map(dim.bottom(Infinity), function(row) { // 3
return row.key;
});
return cols.slice(1).map(function(col) { // 4
var row = {
label: col.label
};
Object.keys(cats).forEach(function(k) {
row[k] = dall.get(k);
});
return row;
});
}
},
cols: [ // 5
{
label: cols[0].label,
format: function(d) {
return d.label;
}
}
].concat(Object.keys(cats).map(function(k) { // 6
return {
label: k,
format: function(d) {
return cols2.get(d.label).format(d[k]);
}
}
}))
};
}
var transposed = transpose_datatable(categories, fakeDim, columns)
Run Code Online (Sandbox Code Playgroud)
d3.map
here,它的行为就像一个行为良好的JavaScript对象。.bottom()
方法,就像上面的方法一样。.bottom()
将需要所有原始数据,并按键(类别名称)索引。因此,我们也将其放入d3.map
对象中。.format()
调用原始列的format
,使用类别名称获取数据。新屏幕截图: