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

How to filter views with an opacity range in d3/dc.js?

我不知道这在 dc.jscrossfilter.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.jscrossfilter.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;

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

您或许可以使用 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 的大部分功能。但是你必须从头开始才能问这个问题。

Updated fiddle.

编辑 2: 按过滤度对点进行排序,如下所示:

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

Fiddle 3