dc.js: 如何交叉过滤复杂对象?
dc.js: How to crossfilter complex object?
我有一个复杂的 JSON 对象,想要交叉过滤数据(键应该是 x 轴,值应该是 y 轴),我该如何处理这个对象?
signalData: {
signal1: {
name: "",
data: {2,3,1,4,5,1,3},
},
signal2: {
name: "",
data: {2,3,1,4,5,1,3},
},
signal3: {
name: "",
data: {2,3,1,4,5,1,3},
},
我认为主要是交叉过滤数据键,因为我想在 3 个不同的图表中使用这些数据。
这里有一张图可能更好地描述了我想做的事情 ;)
这是一些代码:
var data = {
"1": 10,
"2": 20,
"3": 30,
"4": 40,
"5": 50,
"6": 60
};
var dataModel = Object.keys(data).map(function(d) {
return {
key: +d,
value: data[d]
};
});
signalCF = crossfilter(dataModel);
signalDim = signalCF.dimension(dc.pluck("key"));
signalGroup = signalDim.group().reduceSum(function(d) {
return d.value; });
我不确定我们是否使用相同的“过滤器”定义;我的意思是问你是否打算使用crossfilter的过滤功能,即在一个维度上刷并仅在无关视图中看到所选数据。
range/focus 功能不需要过滤,因为所有图表都在同一维度上,没有数据被过滤。
假设您确实要在此数据维度上进行过滤,则需要展平数据。
如果你的原始数据看起来像
signalData: {
signal1: {
name: "",
data: {2,3,1,4,5,1,3},
},
signal2: {
name: "",
data: {2,3,1,4,5,1,3},
},
signal3: {
name: "",
data: {2,3,1,4,5,1,3},
},
您的扁平化数据可能看起来像
[
{
signal1: 2,
signal2: 2,
signal3: 2
},
{
signal1: 3,
signal2: 3,
signal3: 3
},
{
signal1: 1,
signal2: 1,
signal3: 1
},
{
signal1: 4,
signal2: 4,
signal3: 4
},
// ...
这是我想表达的唯一一点,其余的应该是显而易见的...
我对在数组上使用 Object.keys
持谨慎态度。它可能有效,但数据可能会乱序。 d3.range
会做同样的事情。
将密钥添加到上述数据中:
var dataModel = d3.range(0, data.length).map(function(d) {
return {
key: +d,
...data[d]
};
});
现在数据看起来像
[
{
key: 0,
signal1: 2,
signal2: 2,
signal3: 2
},
// ...
您可以像这样定义维度和组:
signalCF = crossfilter(dataModel);
signalDim = signalCF.dimension(dc.pluck("key"));
signalGroup1 = signalDim.group().reduceSum(function(d) {
return d.signal1; });
signalGroup2 = signalDim.group().reduceSum(function(d) {
return d.signal2; });
显然,您也可以编写代码将数据结构扁平化为此类数据。我想表达的唯一一点是 crossfilter 的本机格式是扁平化数组;可以压缩其他格式的数据,但过滤只有在数据是数组时才有效。
这里是一些进行转换的代码。将 column-major 数据旋转为 row-major 数据是一项常见任务,我通常使用 d3.range and Array.reduce,尽管还有其他方法。
function rotate_data(odata) {
const keys = Object.keys(odata),
len = d3.max(keys, key => odata[key].data.length); // 1
if(keys.some(key => odata[key].data.length < len))
console.warn('warning: data not same length; padding with zeros'); // 2
return d3.range(0, len).map(i => keys.reduce(
(p, k) => (p[k] = odata[k].data[i] || 0, p), {key: i}); // 3
}
rotate_data
计算对象 (1) 的所有值的 maximum-length data
字段。如果这些数组中的任何一个不是该长度 (2),它就会发出警告。最后 (3) 它将整数 [1, length) 映射到一个新的对象数组
- 整数
i
的字段key
- 原始对象的每个键的字段,包含相应数组的第
i
个值
我测试了函数here。请注意,您的示例数据中存在拼写错误 - 数组应括在方括号中而不是花括号中。
我有一个复杂的 JSON 对象,想要交叉过滤数据(键应该是 x 轴,值应该是 y 轴),我该如何处理这个对象?
signalData: {
signal1: {
name: "",
data: {2,3,1,4,5,1,3},
},
signal2: {
name: "",
data: {2,3,1,4,5,1,3},
},
signal3: {
name: "",
data: {2,3,1,4,5,1,3},
},
我认为主要是交叉过滤数据键,因为我想在 3 个不同的图表中使用这些数据。
这里有一张图可能更好地描述了我想做的事情 ;)
这是一些代码:
var data = {
"1": 10,
"2": 20,
"3": 30,
"4": 40,
"5": 50,
"6": 60
};
var dataModel = Object.keys(data).map(function(d) {
return {
key: +d,
value: data[d]
};
});
signalCF = crossfilter(dataModel);
signalDim = signalCF.dimension(dc.pluck("key"));
signalGroup = signalDim.group().reduceSum(function(d) {
return d.value; });
我不确定我们是否使用相同的“过滤器”定义;我的意思是问你是否打算使用crossfilter的过滤功能,即在一个维度上刷并仅在无关视图中看到所选数据。
range/focus 功能不需要过滤,因为所有图表都在同一维度上,没有数据被过滤。
假设您确实要在此数据维度上进行过滤,则需要展平数据。
如果你的原始数据看起来像
signalData: {
signal1: {
name: "",
data: {2,3,1,4,5,1,3},
},
signal2: {
name: "",
data: {2,3,1,4,5,1,3},
},
signal3: {
name: "",
data: {2,3,1,4,5,1,3},
},
您的扁平化数据可能看起来像
[
{
signal1: 2,
signal2: 2,
signal3: 2
},
{
signal1: 3,
signal2: 3,
signal3: 3
},
{
signal1: 1,
signal2: 1,
signal3: 1
},
{
signal1: 4,
signal2: 4,
signal3: 4
},
// ...
这是我想表达的唯一一点,其余的应该是显而易见的...
我对在数组上使用 Object.keys
持谨慎态度。它可能有效,但数据可能会乱序。 d3.range
会做同样的事情。
将密钥添加到上述数据中:
var dataModel = d3.range(0, data.length).map(function(d) {
return {
key: +d,
...data[d]
};
});
现在数据看起来像
[
{
key: 0,
signal1: 2,
signal2: 2,
signal3: 2
},
// ...
您可以像这样定义维度和组:
signalCF = crossfilter(dataModel);
signalDim = signalCF.dimension(dc.pluck("key"));
signalGroup1 = signalDim.group().reduceSum(function(d) {
return d.signal1; });
signalGroup2 = signalDim.group().reduceSum(function(d) {
return d.signal2; });
显然,您也可以编写代码将数据结构扁平化为此类数据。我想表达的唯一一点是 crossfilter 的本机格式是扁平化数组;可以压缩其他格式的数据,但过滤只有在数据是数组时才有效。
这里是一些进行转换的代码。将 column-major 数据旋转为 row-major 数据是一项常见任务,我通常使用 d3.range and Array.reduce,尽管还有其他方法。
function rotate_data(odata) {
const keys = Object.keys(odata),
len = d3.max(keys, key => odata[key].data.length); // 1
if(keys.some(key => odata[key].data.length < len))
console.warn('warning: data not same length; padding with zeros'); // 2
return d3.range(0, len).map(i => keys.reduce(
(p, k) => (p[k] = odata[k].data[i] || 0, p), {key: i}); // 3
}
rotate_data
计算对象 (1) 的所有值的 maximum-length data
字段。如果这些数组中的任何一个不是该长度 (2),它就会发出警告。最后 (3) 它将整数 [1, length) 映射到一个新的对象数组
- 整数
i
的字段key
- 原始对象的每个键的字段,包含相应数组的第
i
个值
我测试了函数here。请注意,您的示例数据中存在拼写错误 - 数组应括在方括号中而不是花括号中。