javascript - 使用复选框过滤多列数据 - D3

标签 javascript d3.js

我正在 D3 中创建散点图,我想使用复选框按两个分类变量过滤数据。目前,我可以使用复选框过滤掉数据,但如果我重新选中一个类别中的某个框,它将带回该类别的所有数据,无论其他类别中选中/未选中的内容。我想知道如何最好地同时根据多个变量过滤数据。

这是我的数据和代码的简化版本:

数据(test.csv):

color,texture,length,width
blue,fluffy,4,1
yellow,fluffy,5,2
blue,grainy,3,1
yellow,grainy,4,2
blue,grainy,5,3
yellow,grainy,5,4

HTML:

<!DOCTYPE html>
<meta charset="utf-8">
<html lang="en">
  <body>
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script type="text/javascript" src="test.js"></script>

    <!-- Checkboxes -->
    <div class="filter_options">
        <input class="color_button" id="B" value="blue" type="checkbox"
               checked="checked">Blue</input>
        <input class="color_button" id="Y" value="yellow" type="checkbox"
               checked="checked">Yellow</input>
    </div>
    <div class="filter_options">
        <input class="texture_button" id="F" value="fluffy" type="checkbox"
               checked="checked">Fluffy</input>
        <input class="texture_button" id="G" value="grainy" type="checkbox"
               checked="checked">Grainy</input>
    </div>
  </body>
 </html>

Javascript(test.js;过滤发生在底部):

// Set width/height/margins
var margin = {top: 20, right: 20, bottom: 30, left: 50};
var w = 900 - margin.left - margin.right;
var h = 500 - margin.top - margin.bottom;

// Create SVG
var svg = d3.select("body").append("svg")
        .attr("width", w + margin.left + margin.right)
        .attr("height", h + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");


// x and y scales 
var x = d3.scale.linear()
        .domain([0, 10])
        .range([0, w]);

var y = d3.scale.linear()
        .domain([0, 10])
        .range([h, 0]);

// x axis
var xAxis = d3.svg.axis()
        .ticks(6)
        .scale(x);

// y axis
var yAxis = d3.svg.axis()
        .ticks(7)
        .scale(y)
        .orient("left");

// Colors for points
var col = d3.scale.ordinal()
    .domain(["blue", "yellow"])
    .range(["#3b80e8", "#ecea5f"]);

// Add x axis ("Length")
svg.append("g")
    .attr("class", "axis")
    .attr("transform", "translate(0," + h + ")")
    .call(xAxis)
    .append("text")
    .attr("x", w)
    .attr("y", -6)
    .style("text-anchor", "end")
    .text("Length");

// Add y axis ("Width")
svg.append("g")
    .attr("class", "axis")
    .call(yAxis)
    .append("text")
    .attr("transform", "rotate(-90)")
    .attr("y", 6)
    .attr("dy", ".71em")
    .style("text-anchor", "end")
    .text("Width");

// Data
var dat;
d3.csv("test.csv", function(data) {
    data.forEach(function(d) {
        d.length = +d.length;
        d.width = +d.width;
    });

    // Scatterplot
    svg.selectAll(".dot")
        .data(data)
        .enter()
        .append("circle")
        .attr("class", "dot")
        .attr("cx", function(d) {return x(d.length); })
        .attr("cy", function(d) {return y(d.width); })
        .attr("r", 7)
        .style("fill", function(d) { return col(d.color); });

    // Filter data by color
    d3.selectAll(".color_button").on("change", function() {
        var selected = this.value,
            display = this.checked ? "inline" : "none";

        svg.selectAll(".dot")
            .filter(function(d) { return selected == d.color; })
            .attr("display", display);
    });

    // Filter data by texture
    d3.selectAll(".texture_button").on("change", function() {
        var selected = this.value,
            display = this.checked ? "inline" : "none";

        svg.selectAll(".dot")
            .filter(function(d) { return selected == d.texture; })
            .attr("display", display);
    });

});

在结果图中,如果我取消选中“蓝色”,所有蓝色点都会消失。如果我取消选中“蓬松”,就会多一点消失。如果我然后重新检查“蓬松”,我会得到一个黄色蓬松点和一个蓝色蓬松点。我想我可以明白为什么我编写的代码会发生这种情况:因为当我重新检查“蓬松”时,我没有更改颜色复选框的状态,所以我的数据没有根据颜色。我对 D3 和 Javascript 是全新的,所以我不知道如何更好地同时完成多列的过滤。

最佳答案

这是一种方法。将两个过滤代码片段替换为:

// a function that will be responsible for updating the visibility of the dots
function update() {
  // colors will be the array of active colors, i.e. if only the yellow checkbox
  // is checked, it will be ['yellow']
  var colors = d3.selectAll('.color_button')[0]
     .filter(function(e) { return e.checked; })
     .map(function(e) { return e.value; });

  // same thing for the textures
  var textures = d3.selectAll('.texture_button')[0]
      .filter(function(e) { return e.checked; })
      .map(function(e) { return e.value; });

  // a helper function that will return the correct display value
  // it will be called for every dot
  function display(d) {
    // we check if the current dot's color and texture are present in the
    // colors and textures arrays.
    if (colors.indexOf(d.color) !== -1 && textures.indexOf(d.texture) !== -1) {
      return 'inline';
    } else {
      return 'none';
    }
  }

  // we change the display attribute of every dot using the display function just defined
  svg.selectAll('.dot').attr('display', display);
}

// we add a simple handler to all the checkboxes: every time one changes,
// just call update
d3.selectAll(".filter_options input").on("change", update);

关于javascript - 使用复选框过滤多列数据 - D3,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35388595/

相关文章:

javascript - Sendgrid 入站 webhook 与 Node 和 multer

d3.js - D3 : Add element after delay, 然后转换

javascript - D3 v3 附加复选框?

javascript - 单击按钮时触发两次

JavaScript 面向对象 : Object instantiation and adding properties using different syntaxes

javascript - JavaScript 中的屏幕对象在 QWebEnginePage 中不可用

javascript - jquery - 根据文档宽度折叠面板

javascript - Angular 中的 d3.js - 属性 'event' 在类型 'typeof import 上不存在

d3.js - d3js 在 g 内的文本变换时闪烁

javascript - d3.js 逆气泡图