如何将原始数据行检索到 dc.js 箱线图数据点?
How can I retrieve the original data row to a dc.js boxplot data-point?
我正在使用 dc.js 创建一个按预期工作的箱线图。为了向图表添加更多交互性,我想让用户点击离群值以检索其他信息。
因此我创建了一个事件处理程序,如 D3 documentation 中所述。结果按预期工作,当用户单击数据点时我触发了事件。我的期望是,我将能够以某种方式访问原始数据以检索单击数据点的 sfc 属性,但我失败了,目前不知道如何解决这个问题。任何帮助将不胜感激。
const data = [{
"duration": 248,
"type": "M248",
"sfc": "M248BJ0L2809783",
"pass": 1
},
{
"duration": 249,
"type": "M248",
"sfc": "M248BK0L2809676",
"pass": 1
},
{
"duration": 156,
"type": "M248",
"sfc": "M248BK0L2809676",
"pass": 1
},
{
"duration": 254,
"type": "M248",
"sfc": "M248BP0L2809798",
"pass": 1
},
{
"duration": 134,
"type": "M248",
"sfc": "M248BJ0L2809783",
"pass": 1
},
{
"duration": 128,
"type": "M248",
"sfc": "M248BP0L2809798",
"pass": 0
},
{
"duration": 228,
"type": "M248",
"sfc": "M248B90L2809800",
"pass": 0
},
{
"duration": 125,
"type": "M248",
"sfc": "M248B90L2809800",
"pass": 0
},
{
"duration": 242,
"type": "M248",
"sfc": "M248BJ0L2809792",
"pass": 1
},
{
"duration": 149,
"type": "M248",
"sfc": "M248BJ0L2809792",
"pass": 1
},
{
"duration": 237,
"type": "M248",
"sfc": "M248BJ0L2809819",
"pass": 1
},
{
"duration": 153,
"type": "M248",
"sfc": "M248BJ0L2809819",
"pass": 1
},
{
"duration": 232,
"type": "M248",
"sfc": "M248BK0L2809847",
"pass": 1
},
{
"duration": 482,
"type": "M248",
"sfc": "M248BK0L2809847",
"pass": 1
},
{
"duration": 238,
"type": "M248",
"sfc": "M248BK0L2809883",
"pass": 1
},
{
"duration": 143,
"type": "M248",
"sfc": "M248BK0L2809883",
"pass": 1
},
{
"duration": 213,
"type": "M247",
"sfc": "M247B50L2693004",
"pass": 1
},
{
"duration": 217,
"type": "M247",
"sfc": "M247B50L2693004",
"pass": 0
},
{
"duration": 229,
"type": "M248",
"sfc": "M248BC0L2809902",
"pass": 1
},
{
"duration": 151,
"type": "M248",
"sfc": "M248BC0L2809902",
"pass": 0
}
];
const cycletimeChart = dc.boxPlot('#cycletime-chart');
const ndx = crossfilter(data),
typeDimension = ndx.dimension(function(d) {
return d.type;
}),
cycletimeGroupByType = typeDimension.group().reduce(function(p, v) {
// keep array sorted for efficiency
p.splice(d3.bisectLeft(p, v.duration), 0, v.duration);
return p;
}, function(p, v) {
p.splice(d3.bisectLeft(p, v.duration), 1);
return p;
}, function() {
return [];
});
cycletimeChart
.dimension(typeDimension)
.group(cycletimeGroupByType)
.on('pretransition', function(chart) {
chart.selectAll('circle.outlier').on('click.sfcClick', function(datum, index, nodes) {
console.log(`Clicked on outlier with array index ${datum}, ${index}, ${nodes}.`);
//Here I would like to retrieve the the sfc attribute from the original data object.
});
});
cycletimeChart.render();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Boxplot test</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.16.0/d3.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.min.js"></script>
<script type="text/javascript" src="https://unpkg.com/dc@4/dist/dc.js"></script>
<link rel="stylesheet" type="text/css" href="https://unpkg.com/dc@4/dist/style/dc.css">
</head>
<body>
<div id="cycletime-chart"></div>
</body>
</html>
这里存在三个问题:
- 由于 crossfilter 会聚合数据,因此只有您在 reduce 函数中提供的内容才可用。
- 箱线图将数组索引绑定到异常值,而不是数据。
- 如果这些持续时间不唯一,您将 运行 遇到过滤问题。
1。通过 crossfilter
传递整行
由于crossfilter都是关于聚合的,所以默认情况下原始数据是不可用的。一种解决方法是将缩减更改为存储 v
而不是 v.duration
:
bisectLeft = d3.bisector(d => d.duration).left,
cycletimeGroupByType = typeDimension.group().reduce(function(p, v) {
// keep array sorted for efficiency
p.splice(bisectLeft(p, v.duration), 0, v);
return p;
}, function(p, v) {
p.splice(bisectLeft(p, v.duration), 1);
return p;
}, function() {
return [];
});
由于 dc.boxPlot
需要一个数字数组,您还需要更改 valueAccessor
以提取持续时间:
.valueAccessor(d => d.value.map(r => r.duration))
2。使用数组索引
获取数据
如 中所述,dc.js 箱线图将 数组索引 绑定到离群点。
由于交叉过滤器 key/value 对绑定到父 <g>
元素,可以使用咒语
检索原始数据
d3.select(this.parentNode).datum().value[datum]
3。非唯一持续时间
在第一步中,我们开始在缩减中保存数据行,而不仅仅是持续时间。如果这些持续时间不是唯一的,则会出现问题:当行被过滤掉时,错误的值可能会从数组中删除。
为了更加小心,我们应该扫描确切的值而不是删除具有相同持续时间的第一个条目:
function(p, v) {
let i = d3.bisectLeft(p, v.duration);
while(p[i] !== v) ++i;
p.splice(i, 1);
return p;
}
警告:这是未经测试的,因为您的示例中没有过滤。
const data = [{
"duration": 248,
"type": "M248",
"sfc": "M248BJ0L2809783",
"pass": 1
},
{
"duration": 249,
"type": "M248",
"sfc": "M248BK0L2809676",
"pass": 1
},
{
"duration": 156,
"type": "M248",
"sfc": "M248BK0L2809676",
"pass": 1
},
{
"duration": 254,
"type": "M248",
"sfc": "M248BP0L2809798",
"pass": 1
},
{
"duration": 134,
"type": "M248",
"sfc": "M248BJ0L2809783",
"pass": 1
},
{
"duration": 128,
"type": "M248",
"sfc": "M248BP0L2809798",
"pass": 0
},
{
"duration": 228,
"type": "M248",
"sfc": "M248B90L2809800",
"pass": 0
},
{
"duration": 125,
"type": "M248",
"sfc": "M248B90L2809800",
"pass": 0
},
{
"duration": 242,
"type": "M248",
"sfc": "M248BJ0L2809792",
"pass": 1
},
{
"duration": 149,
"type": "M248",
"sfc": "M248BJ0L2809792",
"pass": 1
},
{
"duration": 237,
"type": "M248",
"sfc": "M248BJ0L2809819",
"pass": 1
},
{
"duration": 153,
"type": "M248",
"sfc": "M248BJ0L2809819",
"pass": 1
},
{
"duration": 232,
"type": "M248",
"sfc": "M248BK0L2809847",
"pass": 1
},
{
"duration": 482,
"type": "M248",
"sfc": "M248BK0L2809847",
"pass": 1
},
{
"duration": 238,
"type": "M248",
"sfc": "M248BK0L2809883",
"pass": 1
},
{
"duration": 143,
"type": "M248",
"sfc": "M248BK0L2809883",
"pass": 1
},
{
"duration": 213,
"type": "M247",
"sfc": "M247B50L2693004",
"pass": 1
},
{
"duration": 217,
"type": "M247",
"sfc": "M247B50L2693004",
"pass": 0
},
{
"duration": 229,
"type": "M248",
"sfc": "M248BC0L2809902",
"pass": 1
},
{
"duration": 151,
"type": "M248",
"sfc": "M248BC0L2809902",
"pass": 0
}
];
const cycletimeChart = dc.boxPlot('#cycletime-chart');
const ndx = crossfilter(data),
typeDimension = ndx.dimension(function(d) {
return d.type;
}),
bisectLeft = d3.bisector(d => d.duration).left,
cycletimeGroupByType = typeDimension.group().reduce(function(p, v) {
// keep array sorted for efficiency
p.splice(bisectLeft(p, v.duration), 0, v);
return p;
}, function(p, v) {
let i = bisectLeft(p, v.duration);
while(p[i] !== v) ++i;
p.splice(i, 1);
return p;
}, function() {
return [];
});
cycletimeChart
.dimension(typeDimension)
.group(cycletimeGroupByType)
.valueAccessor(d => d.value.map(r => r.duration))
.on('pretransition', function(chart) {
chart.selectAll('circle.outlier').on('click.sfcClick', function(datum, index, nodes) {
console.log(`Clicked on outlier with datum, index, nodes ${datum}, ${index}, ${nodes}.`);
console.log('parent array', d3.select(this.parentNode).datum().value);
console.log(`Original datum`, d3.select(this.parentNode).datum().value[datum]);
//Here I would like to retrieve the the sfc attribute from the original data object.
});
});
cycletimeChart.render();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Boxplot test</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.16.0/d3.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.min.js"></script>
<script type="text/javascript" src="https://unpkg.com/dc@4/dist/dc.js"></script>
<link rel="stylesheet" type="text/css" href="https://unpkg.com/dc@4/dist/style/dc.css">
</head>
<body>
<div id="cycletime-chart"></div>
</body>
</html>
我正在使用 dc.js 创建一个按预期工作的箱线图。为了向图表添加更多交互性,我想让用户点击离群值以检索其他信息。
因此我创建了一个事件处理程序,如 D3 documentation 中所述。结果按预期工作,当用户单击数据点时我触发了事件。我的期望是,我将能够以某种方式访问原始数据以检索单击数据点的 sfc 属性,但我失败了,目前不知道如何解决这个问题。任何帮助将不胜感激。
const data = [{
"duration": 248,
"type": "M248",
"sfc": "M248BJ0L2809783",
"pass": 1
},
{
"duration": 249,
"type": "M248",
"sfc": "M248BK0L2809676",
"pass": 1
},
{
"duration": 156,
"type": "M248",
"sfc": "M248BK0L2809676",
"pass": 1
},
{
"duration": 254,
"type": "M248",
"sfc": "M248BP0L2809798",
"pass": 1
},
{
"duration": 134,
"type": "M248",
"sfc": "M248BJ0L2809783",
"pass": 1
},
{
"duration": 128,
"type": "M248",
"sfc": "M248BP0L2809798",
"pass": 0
},
{
"duration": 228,
"type": "M248",
"sfc": "M248B90L2809800",
"pass": 0
},
{
"duration": 125,
"type": "M248",
"sfc": "M248B90L2809800",
"pass": 0
},
{
"duration": 242,
"type": "M248",
"sfc": "M248BJ0L2809792",
"pass": 1
},
{
"duration": 149,
"type": "M248",
"sfc": "M248BJ0L2809792",
"pass": 1
},
{
"duration": 237,
"type": "M248",
"sfc": "M248BJ0L2809819",
"pass": 1
},
{
"duration": 153,
"type": "M248",
"sfc": "M248BJ0L2809819",
"pass": 1
},
{
"duration": 232,
"type": "M248",
"sfc": "M248BK0L2809847",
"pass": 1
},
{
"duration": 482,
"type": "M248",
"sfc": "M248BK0L2809847",
"pass": 1
},
{
"duration": 238,
"type": "M248",
"sfc": "M248BK0L2809883",
"pass": 1
},
{
"duration": 143,
"type": "M248",
"sfc": "M248BK0L2809883",
"pass": 1
},
{
"duration": 213,
"type": "M247",
"sfc": "M247B50L2693004",
"pass": 1
},
{
"duration": 217,
"type": "M247",
"sfc": "M247B50L2693004",
"pass": 0
},
{
"duration": 229,
"type": "M248",
"sfc": "M248BC0L2809902",
"pass": 1
},
{
"duration": 151,
"type": "M248",
"sfc": "M248BC0L2809902",
"pass": 0
}
];
const cycletimeChart = dc.boxPlot('#cycletime-chart');
const ndx = crossfilter(data),
typeDimension = ndx.dimension(function(d) {
return d.type;
}),
cycletimeGroupByType = typeDimension.group().reduce(function(p, v) {
// keep array sorted for efficiency
p.splice(d3.bisectLeft(p, v.duration), 0, v.duration);
return p;
}, function(p, v) {
p.splice(d3.bisectLeft(p, v.duration), 1);
return p;
}, function() {
return [];
});
cycletimeChart
.dimension(typeDimension)
.group(cycletimeGroupByType)
.on('pretransition', function(chart) {
chart.selectAll('circle.outlier').on('click.sfcClick', function(datum, index, nodes) {
console.log(`Clicked on outlier with array index ${datum}, ${index}, ${nodes}.`);
//Here I would like to retrieve the the sfc attribute from the original data object.
});
});
cycletimeChart.render();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Boxplot test</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.16.0/d3.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.min.js"></script>
<script type="text/javascript" src="https://unpkg.com/dc@4/dist/dc.js"></script>
<link rel="stylesheet" type="text/css" href="https://unpkg.com/dc@4/dist/style/dc.css">
</head>
<body>
<div id="cycletime-chart"></div>
</body>
</html>
这里存在三个问题:
- 由于 crossfilter 会聚合数据,因此只有您在 reduce 函数中提供的内容才可用。
- 箱线图将数组索引绑定到异常值,而不是数据。
- 如果这些持续时间不唯一,您将 运行 遇到过滤问题。
1。通过 crossfilter
传递整行由于crossfilter都是关于聚合的,所以默认情况下原始数据是不可用的。一种解决方法是将缩减更改为存储 v
而不是 v.duration
:
bisectLeft = d3.bisector(d => d.duration).left,
cycletimeGroupByType = typeDimension.group().reduce(function(p, v) {
// keep array sorted for efficiency
p.splice(bisectLeft(p, v.duration), 0, v);
return p;
}, function(p, v) {
p.splice(bisectLeft(p, v.duration), 1);
return p;
}, function() {
return [];
});
由于 dc.boxPlot
需要一个数字数组,您还需要更改 valueAccessor
以提取持续时间:
.valueAccessor(d => d.value.map(r => r.duration))
2。使用数组索引
获取数据如
由于交叉过滤器 key/value 对绑定到父 <g>
元素,可以使用咒语
d3.select(this.parentNode).datum().value[datum]
3。非唯一持续时间
在第一步中,我们开始在缩减中保存数据行,而不仅仅是持续时间。如果这些持续时间不是唯一的,则会出现问题:当行被过滤掉时,错误的值可能会从数组中删除。
为了更加小心,我们应该扫描确切的值而不是删除具有相同持续时间的第一个条目:
function(p, v) {
let i = d3.bisectLeft(p, v.duration);
while(p[i] !== v) ++i;
p.splice(i, 1);
return p;
}
警告:这是未经测试的,因为您的示例中没有过滤。
const data = [{
"duration": 248,
"type": "M248",
"sfc": "M248BJ0L2809783",
"pass": 1
},
{
"duration": 249,
"type": "M248",
"sfc": "M248BK0L2809676",
"pass": 1
},
{
"duration": 156,
"type": "M248",
"sfc": "M248BK0L2809676",
"pass": 1
},
{
"duration": 254,
"type": "M248",
"sfc": "M248BP0L2809798",
"pass": 1
},
{
"duration": 134,
"type": "M248",
"sfc": "M248BJ0L2809783",
"pass": 1
},
{
"duration": 128,
"type": "M248",
"sfc": "M248BP0L2809798",
"pass": 0
},
{
"duration": 228,
"type": "M248",
"sfc": "M248B90L2809800",
"pass": 0
},
{
"duration": 125,
"type": "M248",
"sfc": "M248B90L2809800",
"pass": 0
},
{
"duration": 242,
"type": "M248",
"sfc": "M248BJ0L2809792",
"pass": 1
},
{
"duration": 149,
"type": "M248",
"sfc": "M248BJ0L2809792",
"pass": 1
},
{
"duration": 237,
"type": "M248",
"sfc": "M248BJ0L2809819",
"pass": 1
},
{
"duration": 153,
"type": "M248",
"sfc": "M248BJ0L2809819",
"pass": 1
},
{
"duration": 232,
"type": "M248",
"sfc": "M248BK0L2809847",
"pass": 1
},
{
"duration": 482,
"type": "M248",
"sfc": "M248BK0L2809847",
"pass": 1
},
{
"duration": 238,
"type": "M248",
"sfc": "M248BK0L2809883",
"pass": 1
},
{
"duration": 143,
"type": "M248",
"sfc": "M248BK0L2809883",
"pass": 1
},
{
"duration": 213,
"type": "M247",
"sfc": "M247B50L2693004",
"pass": 1
},
{
"duration": 217,
"type": "M247",
"sfc": "M247B50L2693004",
"pass": 0
},
{
"duration": 229,
"type": "M248",
"sfc": "M248BC0L2809902",
"pass": 1
},
{
"duration": 151,
"type": "M248",
"sfc": "M248BC0L2809902",
"pass": 0
}
];
const cycletimeChart = dc.boxPlot('#cycletime-chart');
const ndx = crossfilter(data),
typeDimension = ndx.dimension(function(d) {
return d.type;
}),
bisectLeft = d3.bisector(d => d.duration).left,
cycletimeGroupByType = typeDimension.group().reduce(function(p, v) {
// keep array sorted for efficiency
p.splice(bisectLeft(p, v.duration), 0, v);
return p;
}, function(p, v) {
let i = bisectLeft(p, v.duration);
while(p[i] !== v) ++i;
p.splice(i, 1);
return p;
}, function() {
return [];
});
cycletimeChart
.dimension(typeDimension)
.group(cycletimeGroupByType)
.valueAccessor(d => d.value.map(r => r.duration))
.on('pretransition', function(chart) {
chart.selectAll('circle.outlier').on('click.sfcClick', function(datum, index, nodes) {
console.log(`Clicked on outlier with datum, index, nodes ${datum}, ${index}, ${nodes}.`);
console.log('parent array', d3.select(this.parentNode).datum().value);
console.log(`Original datum`, d3.select(this.parentNode).datum().value[datum]);
//Here I would like to retrieve the the sfc attribute from the original data object.
});
});
cycletimeChart.render();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Boxplot test</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.16.0/d3.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.min.js"></script>
<script type="text/javascript" src="https://unpkg.com/dc@4/dist/dc.js"></script>
<link rel="stylesheet" type="text/css" href="https://unpkg.com/dc@4/dist/style/dc.css">
</head>
<body>
<div id="cycletime-chart"></div>
</body>
</html>