[英]Filter data on multiple columns with checkboxes - D3
我正在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);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.