如何过滤d3 / dc.js中不透明度范围的视图?

时间:2018-04-16 18:04:13

标签: d3.js dc.js crossfilter

我不知道dc.jscrossfilter.js是否可以这样做,但我还是决定问。

我将a scatterplot中的a barChartdc示例合并为一个交互式信息中心:

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();

        });

刷条形图时的结果:

brush

我想更改过滤,以便在刷条形图时,散点图中的刷点将具有不透明度值,在画笔中间为1,并且朝向画笔范围的末尾减小。

其他点(画笔外部)应该是灰色的,而不是像当前脚本中那样不可见。插图:

opacity scatterplot

是否可以使用dc.jscrossfilter.js

PS:附加的散点图不是理想的结果。它不会根据不透明度进行过滤。我只是附上它来显示刷完条形图后其他点(灰色)的样子。

1 个答案:

答案 0 :(得分:2)

我无法使用动画过渡效果,因为我缺少有关如何中断过渡的内容,原始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;

        })
    });
  1. 从条形图中获取当前画笔/过滤器
  2. 它应该是null或者应该是RangedFilter
  3. 找到中点和从中点到画笔边缘的距离
  4. 现在将不透明度应用于散点图中的所有符号
  5. 如果有活动画笔,请应用不透明度(否则为1)
  6. 如果符号位于画笔外部,则不透明度为0
  7. 否则,不透明度基于距中点的距离
  8. 是线性的

    您可以使用d3.ease使用曲线而不是线性地将距离[0,1]映射到不透明度[0,1]。这可能很好,因此它强调了更接近中点的点

    这个演示并不是那么酷,因为数据纯粹是随机的,但它显示了这个想法: https://jsfiddle.net/gordonwoodhull/qq31xcoj/64/

    scatter with opacity based on range

    编辑:好吧,它完全滥用了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';
            })
    

    有了这些数据,看到淡蓝色点和灰色点之间的差异是很棘手的。也许它可以更好地使用非随机数据,也许不是。也许另一种颜色会有所帮助。

    no filtering just brushing 同样,您也可以使用直接D3,因为这会禁用dc.js和crossfilter的大部分功能。但是你必须从头开始问这个问题。

    Updated fiddle.

    编辑2:按照以下过滤方式对点进行排序:

            .sort(function(d) {
              return range && range.isFiltered(d.key[2]) ? 1 : 0;
            })
    

    with sorting

    Fiddle 3