更新 dc.js 数据并重新应用原始过滤器
Updating dc.js data and reapplying original filters
我正在尝试为这个关于如何 replace a crossfilter data restoring dimensions and groups - i.e. reapplying any filters created by the user before data is updated. Here's my stab at implementing the accepted answer. Here's a working jsfiddle.
的问题构建一个可重现的示例
脚本在 3 秒后刷新,从 data1
切换到 data2
。如果您在此之前应用过滤器(例如单击 Mr A
),当图表更新时过滤器为 'remembered',因为正确的元素被突出显示(其他元素变灰)。但过滤器并未应用于其他图表。您需要删除过滤器并重新申请它才能工作(例如删除 2013
饼图)。
我的实现或解决方案本身有问题吗?
<!DOCTYPE html>
<html lang="en">
<head>
<title>dc.js - Example</title>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="http://dc-js.github.io/dc.js/css/dc.css"/>
<script type="text/javascript" src="http://dc-js.github.io/dc.js/js/d3.js"></script>
<script type="text/javascript" src="http://dc-js.github.io/dc.js/js/crossfilter.js"></script>
<script type="text/javascript" src="http://dc-js.github.io/dc.js/js/dc.js"></script>
</head>
<body>
<div id="chart-ring-year"></div>
<div id="chart-row-spenders"></div>
<script type="text/javascript">
var yearRingChart = dc.pieChart("#chart-ring-year"),
spenderRowChart = dc.rowChart("#chart-row-spenders");
var data1 = [
{Name: 'Mr A', Spent: 40, Year: 2011},
{Name: 'Mr B', Spent: 10, Year: 2011},
{Name: 'Mr C', Spent: 40, Year: 2011},
{Name: 'Mr A', Spent: 70, Year: 2012},
{Name: 'Mr B', Spent: 20, Year: 2012},
{Name: 'Mr B', Spent: 50, Year: 2013},
{Name: 'Mr C', Spent: 30, Year: 2013}
];
var data2 = [
{Name: 'Mr A', Spent: 10, Year: 2011},
{Name: 'Mr B', Spent: 20, Year: 2011},
{Name: 'Mr C', Spent: 50, Year: 2011},
{Name: 'Mr A', Spent: 20, Year: 2012},
{Name: 'Mr B', Spent: 40, Year: 2012},
{Name: 'Mr B', Spent: 50, Year: 2013},
{Name: 'Mr C', Spent: 50, Year: 2013}
];
// data reset function (adapted)
function resetData(ndx, dimensions) {
dimensions.forEach(function(dim){dim.filter(null);});
ndx.remove();
}
// set crossfilter with first dataset
var ndx = crossfilter(data1),
yearDim = ndx.dimension(function(d) {return +d.Year;}),
spendDim = ndx.dimension(function(d) {return Math.floor(d.Spent/10);}),
nameDim = ndx.dimension(function(d) {return d.Name;}),
spendPerYear = yearDim.group().reduceSum(function(d) {return +d.Spent;}),
spendPerName = nameDim.group().reduceSum(function(d) {return +d.Spent;}),
spendHist = spendDim.group().reduceCount();
function render_plots(){
yearRingChart
.width(200).height(200)
.dimension(yearDim)
.group(spendPerYear)
.innerRadius(50);
spenderRowChart
.width(250).height(200)
.dimension(nameDim)
.group(spendPerName)
.elasticX(true);
dc.renderAll();
}
render_plots();
// REFRESH DATA AFTER 3 SECONDS
setTimeout(function() {
console.log("data reset");
resetData(ndx, [yearDim, spendDim, nameDim]);
ndx = crossfilter(data2),
yearDim = ndx.dimension(function(d) {return +d.Year;}),
spendDim = ndx.dimension(function(d) {return Math.floor(d.Spent/10);}),
nameDim = ndx.dimension(function(d) {return d.Name;}),
spendPerYear = yearDim.group().reduceSum(function(d) {return +d.Spent;}),
spendPerName = nameDim.group().reduceSum(function(d) {return +d.Spent;}),
x = spendPerName,
spendHist = spendDim.group().reduceCount();
render_plots();
}, 3000);
</script>
</body>
</html>
这是您的示例:http://jsfiddle.net/pm12xf3z/
有几个问题已得到纠正,但最重要的是,不要重建您的 Crossfilter、您的维度或您的组。那是不必要的。现有维度和组将使用新数据进行更新。
只需从您的 Crossfilter 中删除旧数据(ndx.remove()
,没有任何过滤器),然后添加您的新数据 (ndx.add(data2)
),然后告诉 dc.js 自行更新 ( dc.redrawAll()
)。这就是您需要对 Crossfilter 执行的所有操作。
那么问题是您如何删除所有过滤器并在此过程中维护您的 dc.js 过滤器?关键是与您的 dc.js 图表互动,而不是直接与您的维度互动。对于顺序选择图表,您可以执行以下操作:
function resetData(ndx, dimensions) {
var yearChartFilters = yearRingChart.filters();
var spenderChartFilters = spenderRowChart.filters();
yearRingChart.filter(null);
spenderRowChart.filter(null);
ndx.remove();
yearRingChart.filter([yearChartFilters]);
spenderRowChart.filter([spenderChartFilters]);
}
也就是说,从图表中获取过滤器,将图表上的过滤器设置为 null
,执行 Crossfilter 数据删除,然后将过滤器添加回图表。确切的过滤器格式有点古怪,而且你必须将 .filters() 的输出放在一个数组中以使其与 .filter() 一起使用这一事实有点奇怪,但事情在 dc.js 2.0 测试版。
我正在尝试为这个关于如何 replace a crossfilter data restoring dimensions and groups - i.e. reapplying any filters created by the user before data is updated. Here's my stab at implementing the accepted answer. Here's a working jsfiddle.
的问题构建一个可重现的示例脚本在 3 秒后刷新,从 data1
切换到 data2
。如果您在此之前应用过滤器(例如单击 Mr A
),当图表更新时过滤器为 'remembered',因为正确的元素被突出显示(其他元素变灰)。但过滤器并未应用于其他图表。您需要删除过滤器并重新申请它才能工作(例如删除 2013
饼图)。
我的实现或解决方案本身有问题吗?
<!DOCTYPE html>
<html lang="en">
<head>
<title>dc.js - Example</title>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="http://dc-js.github.io/dc.js/css/dc.css"/>
<script type="text/javascript" src="http://dc-js.github.io/dc.js/js/d3.js"></script>
<script type="text/javascript" src="http://dc-js.github.io/dc.js/js/crossfilter.js"></script>
<script type="text/javascript" src="http://dc-js.github.io/dc.js/js/dc.js"></script>
</head>
<body>
<div id="chart-ring-year"></div>
<div id="chart-row-spenders"></div>
<script type="text/javascript">
var yearRingChart = dc.pieChart("#chart-ring-year"),
spenderRowChart = dc.rowChart("#chart-row-spenders");
var data1 = [
{Name: 'Mr A', Spent: 40, Year: 2011},
{Name: 'Mr B', Spent: 10, Year: 2011},
{Name: 'Mr C', Spent: 40, Year: 2011},
{Name: 'Mr A', Spent: 70, Year: 2012},
{Name: 'Mr B', Spent: 20, Year: 2012},
{Name: 'Mr B', Spent: 50, Year: 2013},
{Name: 'Mr C', Spent: 30, Year: 2013}
];
var data2 = [
{Name: 'Mr A', Spent: 10, Year: 2011},
{Name: 'Mr B', Spent: 20, Year: 2011},
{Name: 'Mr C', Spent: 50, Year: 2011},
{Name: 'Mr A', Spent: 20, Year: 2012},
{Name: 'Mr B', Spent: 40, Year: 2012},
{Name: 'Mr B', Spent: 50, Year: 2013},
{Name: 'Mr C', Spent: 50, Year: 2013}
];
// data reset function (adapted)
function resetData(ndx, dimensions) {
dimensions.forEach(function(dim){dim.filter(null);});
ndx.remove();
}
// set crossfilter with first dataset
var ndx = crossfilter(data1),
yearDim = ndx.dimension(function(d) {return +d.Year;}),
spendDim = ndx.dimension(function(d) {return Math.floor(d.Spent/10);}),
nameDim = ndx.dimension(function(d) {return d.Name;}),
spendPerYear = yearDim.group().reduceSum(function(d) {return +d.Spent;}),
spendPerName = nameDim.group().reduceSum(function(d) {return +d.Spent;}),
spendHist = spendDim.group().reduceCount();
function render_plots(){
yearRingChart
.width(200).height(200)
.dimension(yearDim)
.group(spendPerYear)
.innerRadius(50);
spenderRowChart
.width(250).height(200)
.dimension(nameDim)
.group(spendPerName)
.elasticX(true);
dc.renderAll();
}
render_plots();
// REFRESH DATA AFTER 3 SECONDS
setTimeout(function() {
console.log("data reset");
resetData(ndx, [yearDim, spendDim, nameDim]);
ndx = crossfilter(data2),
yearDim = ndx.dimension(function(d) {return +d.Year;}),
spendDim = ndx.dimension(function(d) {return Math.floor(d.Spent/10);}),
nameDim = ndx.dimension(function(d) {return d.Name;}),
spendPerYear = yearDim.group().reduceSum(function(d) {return +d.Spent;}),
spendPerName = nameDim.group().reduceSum(function(d) {return +d.Spent;}),
x = spendPerName,
spendHist = spendDim.group().reduceCount();
render_plots();
}, 3000);
</script>
</body>
</html>
这是您的示例:http://jsfiddle.net/pm12xf3z/
有几个问题已得到纠正,但最重要的是,不要重建您的 Crossfilter、您的维度或您的组。那是不必要的。现有维度和组将使用新数据进行更新。
只需从您的 Crossfilter 中删除旧数据(ndx.remove()
,没有任何过滤器),然后添加您的新数据 (ndx.add(data2)
),然后告诉 dc.js 自行更新 ( dc.redrawAll()
)。这就是您需要对 Crossfilter 执行的所有操作。
那么问题是您如何删除所有过滤器并在此过程中维护您的 dc.js 过滤器?关键是与您的 dc.js 图表互动,而不是直接与您的维度互动。对于顺序选择图表,您可以执行以下操作:
function resetData(ndx, dimensions) {
var yearChartFilters = yearRingChart.filters();
var spenderChartFilters = spenderRowChart.filters();
yearRingChart.filter(null);
spenderRowChart.filter(null);
ndx.remove();
yearRingChart.filter([yearChartFilters]);
spenderRowChart.filter([spenderChartFilters]);
}
也就是说,从图表中获取过滤器,将图表上的过滤器设置为 null
,执行 Crossfilter 数据删除,然后将过滤器添加回图表。确切的过滤器格式有点古怪,而且你必须将 .filters() 的输出放在一个数组中以使其与 .filter() 一起使用这一事实有点奇怪,但事情在 dc.js 2.0 测试版。