如何在 d3/dc.js 中过滤具有不透明度范围的视图?
How to filter views with an opacity range in d3/dc.js?
我不知道这在 dc.js
和 crossfilter.js
中是否可行,但我还是决定问问。
我结合 a scatterplot and a barChart example from dc 制作了一个交互式仪表板:
var chart1 = dc.scatterPlot("#test1");
var chart2 = dc.scatterPlot("#test2");
d3.csv("output.csv", function(error, data) {
data.forEach(function (x) {
x.x = +x.x;
x.y = +x.y;
x.z = +x.z;
});
var ndx = crossfilter(data),
dim1 = ndx.dimension(function (d) {
return [d.x, d.y];
}),
dim2 = ndx.dimension(function (d) {
return Math.floor(parseFloat(d.z) * 10) / 10;
}),
group1 = dim1.group(),
group2 = dim2.group(),
chart1.width(300)
.height(300)
.x(d3.scale.linear().domain([-2, 2]))
.y(d3.scale.linear().domain([-2, 2]))
.yAxisLabel("y")
.xAxisLabel("x")
.clipPadding(10)
.dimension(dim1)
//.excludedOpacity(0.5)
.excludedColor('#ddd')
.group(group1)
.symbolSize([2.5]);
chart2
.width(600)
.dimension(dim2)
.group(group2)
.x(d3.scale.linear().domain([0,3]))
.elasticY(true)
.controlsUseVisibility(false)
.barPadding([0.1])
.outerPadding([0.05]);
chart2.xAxis().tickFormat(function(d) {return d}); // convert back to base unit
chart2.yAxis().ticks(10);
dc.renderAll();
});
刷条形图结果:
我想改变过滤方式,在刷条形图的时候,散点图中被刷过的点会有一个不透明度值,在刷子中间为1,向刷子范围的末端递减.
其他点(画笔外)应该是灰色的,而不是像当前脚本中那样不可见。插图:
这可能与 dc.js
和 crossfilter.js
相关吗?
PS:所附的散点图不是您想要的结果。它不会根据不透明度进行过滤。我只是附上它来显示刷条形图后其他点(灰色)应该是什么样子。
我无法使用动画过渡,因为我缺少有关如何中断过渡的内容,而原始 dc.scatterPlot
已经在应用不透明度过渡。
所以,首先,让我们在原始散点图上打开转换:
chart1
.transitionDuration(0)
我们还需要将 Z 添加到散点图的输入数据中。虽然将它添加到值中更有意义,但将它添加到键中很容易(散点图将忽略键中的额外元素):
dim1 = ndx.dimension(function (d) {
return [d.x, d.y, d.z];
}),
然后我们可以向散点图添加一个处理程序,以根据条形图中过滤器的范围对点应用不透明度:
chart1.on('pretransition', function(chart) {
var range = chart2.filter(); // 1
console.assert(!range || range.filterType==='RangedFilter'); // 2
var mid, div; // 3
if(range) {
mid = (range[0] + range[1])/2;
div = (range[1] - range[0])/2;
}
chart1.selectAll('path.symbol') // 4
.attr('opacity', function(d) {
if(range) { // 5
if(d.key[2] < range[0] || range[1] < d.key[2])
op = 0; // 6
else
op = 1 - Math.abs(d.key[2] - mid)/div; // 7
//console.log(mid, div, d.key[2], op);
return op;
}
else return 1;
})
});
- 从条形图
获取当前brush/filter
- 它应该是
null
或者它应该是 RangedFilter
- 找到画笔的中点和中点到边缘的距离
- 现在对散点图中的所有符号应用不透明度
- 如果有活动画笔,应用不透明度(否则为 1)
- 如果符号在画笔外,不透明度为0
- 否则不透明度根据与中点的距离呈线性
您或许可以使用 d3.ease 使用曲线而不是线性将距离 [0,1] 映射到不透明度 [0,1]。这可能很好,因为它强调了靠近中点的点
这个演示不是很酷,因为数据是纯随机的,但它展示了这个想法:
https://jsfiddle.net/gordonwoodhull/qq31xcoj/64/
编辑: 好吧,这完全是对 dc.js 的滥用,但如果你真的想在不过滤的情况下使用它,并以灰色显示排除的点,你也可以做到。
这将禁用条形图上的过滤:
chart2.filterHandler(function(_, filters) { return filters; });
然后像这样对散点图应用不透明度和颜色:
chart1.selectAll('path.symbol')
.attr('opacity', function(d) {
if(range && range.isFiltered(d.key[2]))
return 1 - Math.abs(d.key[2] - mid)/div;
else return 1;
})
.attr('fill', function(d) {
if(!range || range.isFiltered(d.key[2]))
return chart1.getColor(d);
else return '#ccc';
})
根据这些数据,很难看出浅蓝色点和灰色点之间的区别。也许它会更好地处理非随机数据,也许不会。也许另一种颜色会有所帮助。
同样,您也可以直接使用 D3,因为这会禁用 dc.js 和 crossfilter 的大部分功能。但是你必须从头开始才能问这个问题。
编辑 2: 按过滤度对点进行排序,如下所示:
.sort(function(d) {
return range && range.isFiltered(d.key[2]) ? 1 : 0;
})
我不知道这在 dc.js
和 crossfilter.js
中是否可行,但我还是决定问问。
我结合 a scatterplot and a barChart example from dc 制作了一个交互式仪表板:
var chart1 = dc.scatterPlot("#test1");
var chart2 = dc.scatterPlot("#test2");
d3.csv("output.csv", function(error, data) {
data.forEach(function (x) {
x.x = +x.x;
x.y = +x.y;
x.z = +x.z;
});
var ndx = crossfilter(data),
dim1 = ndx.dimension(function (d) {
return [d.x, d.y];
}),
dim2 = ndx.dimension(function (d) {
return Math.floor(parseFloat(d.z) * 10) / 10;
}),
group1 = dim1.group(),
group2 = dim2.group(),
chart1.width(300)
.height(300)
.x(d3.scale.linear().domain([-2, 2]))
.y(d3.scale.linear().domain([-2, 2]))
.yAxisLabel("y")
.xAxisLabel("x")
.clipPadding(10)
.dimension(dim1)
//.excludedOpacity(0.5)
.excludedColor('#ddd')
.group(group1)
.symbolSize([2.5]);
chart2
.width(600)
.dimension(dim2)
.group(group2)
.x(d3.scale.linear().domain([0,3]))
.elasticY(true)
.controlsUseVisibility(false)
.barPadding([0.1])
.outerPadding([0.05]);
chart2.xAxis().tickFormat(function(d) {return d}); // convert back to base unit
chart2.yAxis().ticks(10);
dc.renderAll();
});
刷条形图结果:
我想改变过滤方式,在刷条形图的时候,散点图中被刷过的点会有一个不透明度值,在刷子中间为1,向刷子范围的末端递减.
其他点(画笔外)应该是灰色的,而不是像当前脚本中那样不可见。插图:
这可能与 dc.js
和 crossfilter.js
相关吗?
PS:所附的散点图不是您想要的结果。它不会根据不透明度进行过滤。我只是附上它来显示刷条形图后其他点(灰色)应该是什么样子。
我无法使用动画过渡,因为我缺少有关如何中断过渡的内容,而原始 dc.scatterPlot
已经在应用不透明度过渡。
所以,首先,让我们在原始散点图上打开转换:
chart1
.transitionDuration(0)
我们还需要将 Z 添加到散点图的输入数据中。虽然将它添加到值中更有意义,但将它添加到键中很容易(散点图将忽略键中的额外元素):
dim1 = ndx.dimension(function (d) {
return [d.x, d.y, d.z];
}),
然后我们可以向散点图添加一个处理程序,以根据条形图中过滤器的范围对点应用不透明度:
chart1.on('pretransition', function(chart) {
var range = chart2.filter(); // 1
console.assert(!range || range.filterType==='RangedFilter'); // 2
var mid, div; // 3
if(range) {
mid = (range[0] + range[1])/2;
div = (range[1] - range[0])/2;
}
chart1.selectAll('path.symbol') // 4
.attr('opacity', function(d) {
if(range) { // 5
if(d.key[2] < range[0] || range[1] < d.key[2])
op = 0; // 6
else
op = 1 - Math.abs(d.key[2] - mid)/div; // 7
//console.log(mid, div, d.key[2], op);
return op;
}
else return 1;
})
});
- 从条形图 获取当前brush/filter
- 它应该是
null
或者它应该是 RangedFilter - 找到画笔的中点和中点到边缘的距离
- 现在对散点图中的所有符号应用不透明度
- 如果有活动画笔,应用不透明度(否则为 1)
- 如果符号在画笔外,不透明度为0
- 否则不透明度根据与中点的距离呈线性
您或许可以使用 d3.ease 使用曲线而不是线性将距离 [0,1] 映射到不透明度 [0,1]。这可能很好,因为它强调了靠近中点的点
这个演示不是很酷,因为数据是纯随机的,但它展示了这个想法: https://jsfiddle.net/gordonwoodhull/qq31xcoj/64/
编辑: 好吧,这完全是对 dc.js 的滥用,但如果你真的想在不过滤的情况下使用它,并以灰色显示排除的点,你也可以做到。
这将禁用条形图上的过滤:
chart2.filterHandler(function(_, filters) { return filters; });
然后像这样对散点图应用不透明度和颜色:
chart1.selectAll('path.symbol')
.attr('opacity', function(d) {
if(range && range.isFiltered(d.key[2]))
return 1 - Math.abs(d.key[2] - mid)/div;
else return 1;
})
.attr('fill', function(d) {
if(!range || range.isFiltered(d.key[2]))
return chart1.getColor(d);
else return '#ccc';
})
根据这些数据,很难看出浅蓝色点和灰色点之间的区别。也许它会更好地处理非随机数据,也许不会。也许另一种颜色会有所帮助。
编辑 2: 按过滤度对点进行排序,如下所示:
.sort(function(d) {
return range && range.isFiltered(d.key[2]) ? 1 : 0;
})