如何在动态增长的数据集上应用刷亮?
How to apply brushing on a dynamically growing dataset?
我有一个动态增长的时间序列,我需要在 zoomable/panable 图表中显示。
在这里试试(事实上:我的第一个 jsFiddle :)):
https://jsfiddle.net/Herkules001/L12k5zwx/29/
我尝试按照此处描述的方式进行操作:https://dc-js.github.io/dc.js/examples/replacing-data.html
但是,每次图表更新时,焦点图表上的缩放和过滤器都会丢失。 (然而,画笔保留在范围图表上。)
如何在不重置视图和不丢失缩放比例的情况下添加数据?
var chart = dc.lineChart("#test");
var zoom = dc.lineChart("#zoom");
//d3.csv("morley.csv", function(error, experiments) {
var experiments = d3.csvParse(d3.select('pre#data').text());
experiments.forEach(function(x) {
x.Speed = +x.Speed;
});
var ndx = crossfilter(experiments),
runDimension = ndx.dimension(function(d) {return +d.Run;}),
speedSumGroup = runDimension.group().reduceSum(function(d) {return d.Speed * d.Run / 1000;});
chart
.width(768)
.height(400)
.x(d3.scaleLinear().domain([6,20]))
.brushOn(false)
.yAxisLabel("This is the Y Axis!")
.dimension(runDimension)
.group(speedSumGroup)
.rangeChart(zoom);
zoom
.width(768)
.height(80)
.x(d3.scaleLinear().domain([6,20]))
.brushOn(true)
.yAxisLabel("")
.dimension(runDimension)
.group(speedSumGroup);
zoom.render();
chart.render();
var run = 21;
setInterval(
() => {
var chartfilter = chart.filters();
var zoomfilter = zoom.filters();
chart.filter(null);
zoom.filter(null);
ndx.add([{Expt: 6, Run: run++, Speed: 100 + 5 * run}]);
chart.x(d3.scaleLinear().domain([6,run]));
zoom.x(d3.scaleLinear().domain([6,run]));
chart.filter([chartfilter]);
zoom.filter([zoomfilter]);
chart.render();
zoom.render();
},
1000);
//});
在这种情况下,如果您只是添加数据,则不需要执行您引用的示例中演示的复杂的过滤器清除和恢复操作。
该部分是必需的,因为 crossfilter.remove()
最初会删除与当前过滤器匹配的数据。一个尴尬的界面,几乎不是你想要的。
如果您只是添加数据,则不必担心这些:
setInterval(
() => {
ndx.add([{Expt: 6, Run: run++, Speed: 5000 + 5 * run}]);
chart.redraw();
zoom.redraw();
},
5000);
请注意,通过使用 redraw
而不是 render
,您将获得更少的闪烁和良好的动画过渡。我还添加了 evadeDomainFilter 以避免在图表边缘之前截断线条。
正在删除数据
如果您使用 crossfilter.remove()
的谓词形式,您不必担心保存和恢复过滤器:
ndx.remove(d => d.Run < run-20);
然而,这确实暴露了 dc.js 中的其他错误。似乎 elasticY
不起作用,类似于 in this issue. And you get some weird animations.
所描述的
Here's a demo with remove enabled.
最后,dc.js 有一些非常简洁的功能,通常有办法让它做你想做的事,但它确实很古怪。这是一个非常复杂的领域,根据我的经验,您会在任何功能齐全的图表库中发现其中的一些怪癖。
更新:我修复了 replacing data example,那个现在只有 ndx.remove(() => true)
。
缩放问题
正如 Joerg 在评论中指出的那样,
- 当图表未缩放时,最好让它在新数据到达时也能显示出来
- 如果焦点到达图表的原始域之外,X 域将被剪裁甚至反转
我们可以通过添加 preRedraw event handler 来解决这些问题。那是调整域的理想位置;例如,如果需要,您可以手动实施 elasticX
。 (您马上就会看到,我们做到了!)
首先,简单易懂的幼稚尝试:
chart.on('preRedraw', () => {
chart.elasticX(!zoom.filters().length);
});
我们可以根据范围图表是否具有活动过滤器来打开和关闭 elasticX
。
这行得通而且简单又好用,但是当您尝试关注原始图表中不存在的域时,为什么图表会变得如此混乱?
Welp,它记录了原始域 (source)。这样它可以在焦点被清除时恢复到该域,并且还可以阻止您缩放或平移超过图形的边缘。
但是从上面的来源 link 可以看出我们有一个逃生口。设置X尺度时,记录原始域。所以,不用设置elasticX
,我们可以计算数据的范围,设置比例尺的域,告诉图表比例尺是新的:
chart.on('preRedraw', () => {
if(!zoom.filters().length) {
var xExtent = d3.extent(speedSumGroup.all(), kv => kv.key);
chart.x(chart.x().domain(xExtent));
}
});
New fiddle with zooming issues fixed.
Joerg 指出还有一个问题:如果您在数据输入时移动画笔,画笔手柄偶尔会偏离画笔的末端。根据我的经验,这类故障在 D3(以及一般的动态图表)中非常常见,因为很难考虑用户交互期间数据的变化。它可能可以在库中修复(也许是中断的转换?)但我不打算在这里讨论。
我有一个动态增长的时间序列,我需要在 zoomable/panable 图表中显示。
在这里试试(事实上:我的第一个 jsFiddle :)):
https://jsfiddle.net/Herkules001/L12k5zwx/29/
我尝试按照此处描述的方式进行操作:https://dc-js.github.io/dc.js/examples/replacing-data.html
但是,每次图表更新时,焦点图表上的缩放和过滤器都会丢失。 (然而,画笔保留在范围图表上。)
如何在不重置视图和不丢失缩放比例的情况下添加数据?
var chart = dc.lineChart("#test");
var zoom = dc.lineChart("#zoom");
//d3.csv("morley.csv", function(error, experiments) {
var experiments = d3.csvParse(d3.select('pre#data').text());
experiments.forEach(function(x) {
x.Speed = +x.Speed;
});
var ndx = crossfilter(experiments),
runDimension = ndx.dimension(function(d) {return +d.Run;}),
speedSumGroup = runDimension.group().reduceSum(function(d) {return d.Speed * d.Run / 1000;});
chart
.width(768)
.height(400)
.x(d3.scaleLinear().domain([6,20]))
.brushOn(false)
.yAxisLabel("This is the Y Axis!")
.dimension(runDimension)
.group(speedSumGroup)
.rangeChart(zoom);
zoom
.width(768)
.height(80)
.x(d3.scaleLinear().domain([6,20]))
.brushOn(true)
.yAxisLabel("")
.dimension(runDimension)
.group(speedSumGroup);
zoom.render();
chart.render();
var run = 21;
setInterval(
() => {
var chartfilter = chart.filters();
var zoomfilter = zoom.filters();
chart.filter(null);
zoom.filter(null);
ndx.add([{Expt: 6, Run: run++, Speed: 100 + 5 * run}]);
chart.x(d3.scaleLinear().domain([6,run]));
zoom.x(d3.scaleLinear().domain([6,run]));
chart.filter([chartfilter]);
zoom.filter([zoomfilter]);
chart.render();
zoom.render();
},
1000);
//});
在这种情况下,如果您只是添加数据,则不需要执行您引用的示例中演示的复杂的过滤器清除和恢复操作。
该部分是必需的,因为 crossfilter.remove()
最初会删除与当前过滤器匹配的数据。一个尴尬的界面,几乎不是你想要的。
如果您只是添加数据,则不必担心这些:
setInterval(
() => {
ndx.add([{Expt: 6, Run: run++, Speed: 5000 + 5 * run}]);
chart.redraw();
zoom.redraw();
},
5000);
请注意,通过使用 redraw
而不是 render
,您将获得更少的闪烁和良好的动画过渡。我还添加了 evadeDomainFilter 以避免在图表边缘之前截断线条。
正在删除数据
如果您使用 crossfilter.remove()
的谓词形式,您不必担心保存和恢复过滤器:
ndx.remove(d => d.Run < run-20);
然而,这确实暴露了 dc.js 中的其他错误。似乎 elasticY
不起作用,类似于 in this issue. And you get some weird animations.
Here's a demo with remove enabled.
最后,dc.js 有一些非常简洁的功能,通常有办法让它做你想做的事,但它确实很古怪。这是一个非常复杂的领域,根据我的经验,您会在任何功能齐全的图表库中发现其中的一些怪癖。
更新:我修复了 replacing data example,那个现在只有 ndx.remove(() => true)
。
缩放问题
正如 Joerg 在评论中指出的那样,
- 当图表未缩放时,最好让它在新数据到达时也能显示出来
- 如果焦点到达图表的原始域之外,X 域将被剪裁甚至反转
我们可以通过添加 preRedraw event handler 来解决这些问题。那是调整域的理想位置;例如,如果需要,您可以手动实施 elasticX
。 (您马上就会看到,我们做到了!)
首先,简单易懂的幼稚尝试:
chart.on('preRedraw', () => {
chart.elasticX(!zoom.filters().length);
});
我们可以根据范围图表是否具有活动过滤器来打开和关闭 elasticX
。
这行得通而且简单又好用,但是当您尝试关注原始图表中不存在的域时,为什么图表会变得如此混乱?
Welp,它记录了原始域 (source)。这样它可以在焦点被清除时恢复到该域,并且还可以阻止您缩放或平移超过图形的边缘。
但是从上面的来源 link 可以看出我们有一个逃生口。设置X尺度时,记录原始域。所以,不用设置elasticX
,我们可以计算数据的范围,设置比例尺的域,告诉图表比例尺是新的:
chart.on('preRedraw', () => {
if(!zoom.filters().length) {
var xExtent = d3.extent(speedSumGroup.all(), kv => kv.key);
chart.x(chart.x().domain(xExtent));
}
});
New fiddle with zooming issues fixed.
Joerg 指出还有一个问题:如果您在数据输入时移动画笔,画笔手柄偶尔会偏离画笔的末端。根据我的经验,这类故障在 D3(以及一般的动态图表)中非常常见,因为很难考虑用户交互期间数据的变化。它可能可以在库中修复(也许是中断的转换?)但我不打算在这里讨论。