2016-10-10 230 views
2

我一直在网上搜索,但我无法找到我要找的东西。我想也许我没有使用正确的术语。如何用D3.js过滤数据?

我在D3.js中有一个简单的散点图。我的csv文件是这样的:

Group, X, Y 

1, 4.5, 8 
1, 9, 12 
1, 2, 19 
2, 9, 20 
3, 2, 1 
3, 8, 2 

我想按组筛选。所以,该图将默认显示组1的唯一值,但你也可以选择查看组2或组3

这里的值是一些代码,我已经......

var margin = {top: 20, right: 20, bottom: 30, left: 40}, 
    width = 960 - margin.left - margin.right, 
    height = 500 - margin.top - margin.bottom; 

var x = d3.scale.linear() 
    .range([0, width]); 

var y = d3.scale.linear() 
    .range([height, 0]); 

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

d3.csv("l2data.csv", function(error, data) { 
    if (error) throw error; 

    // Coerce the strings to numbers. 
    data.forEach(function(d) { 
    d.x = +d.x; 
    d.y = +d.y; 
    }); 

    // Compute the scales’ domains. 
    x.domain(d3.extent(data, function(d) { return d.x; })).nice(); 
    y.domain(d3.extent(data, function(d) { return d.y; })).nice(); 

    // Add the x-axis. 
    svg.append("g") 
     .attr("class", "x axis") 
     .attr("transform", "translate(0," + height + ")") 
     .call(d3.svg.axis().scale(x).orient("bottom")); 

    // Add the y-axis. 
    svg.append("g") 
     .attr("class", "y axis") 
     .call(d3.svg.axis().scale(y).orient("left")); 

    // Add the points! 
    svg.selectAll(".point") 
     .data(data) 
    .enter().append("path") 
     .attr("class", "point") 
     .attr("d", d3.svg.symbol().type("triangle-up")) 
     .attr("transform", function(d) { return "translate(" + x(d.x) + "," + y(d.y) + ")"; }); 
}); 

回答

1

这取决于你究竟需要做什么,但你可以像下面的代码片段那样根据你的问题做出来。我跳过了数据加载,但原理是一样的。

您必须创建一个变量来保存创建的点,然后使用选择列表或其他来隐藏或显示基于选择的点。

// this variable will hold your created symbols 
 
var points, 
 
    margin = {top: 20, right: 20, bottom: 30, left: 40}, 
 
    width = 400 - margin.left - margin.right, 
 
    height = 300 - margin.top - margin.bottom; 
 

 
var x = d3.scale.linear() 
 
.range([0, width]); 
 

 
var y = d3.scale.linear() 
 
.range([height, 0]); 
 

 
var select = d3.select('body') 
 
    .append('div') 
 
    .append('select') 
 
    .on('change', function(){ 
 
     // get selected group 
 
     var group = select.property('value'); 
 
     // hide those points based on the selected value. 
 
     points.style('opacity', function(d){ 
 
     return d.group == group ? 1:0; 
 
     }); 
 
    }); 
 

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

 
var data = [ 
 
     {group:1, x:4.5, y:8}, 
 
     {group:1, x:9, y:12}, 
 
     {group:1, x:2, y:19}, 
 
     {group:2, x:9, y:20}, 
 
     {group:3, x:2, y:1}, 
 
     {group:3, x:8, y:2} 
 
    ]; 
 

 
// Coerce the strings to numbers. 
 
data.forEach(function(d) { 
 
    d.x = +d.x; 
 
    d.y = +d.y; 
 
}); 
 

 
var groups = d3.set(data.map(function(d){ return d.group; })).values(); 
 

 
// create group filtering select list 
 
select.selectAll('option') 
 
    .data(groups) 
 
    .enter().append('option').text(function(d){ return d }); 
 

 
select.property('value', groups[0]); // default selected group 
 

 

 
// Compute the scales’ domains. 
 
x.domain(d3.extent(data, function(d) { return d.x; })).nice(); 
 
y.domain(d3.extent(data, function(d) { return d.y; })).nice(); 
 

 
// Add the x-axis. 
 
svg.append("g") 
 
    .attr("class", "x axis") 
 
    .attr("transform", "translate(0," + height + ")") 
 
    .call(d3.svg.axis().scale(x).orient("bottom")); 
 

 
// Add the y-axis. 
 
svg.append("g") 
 
    .attr("class", "y axis") 
 
    .call(d3.svg.axis().scale(y).orient("left")); 
 

 
// Add the points! 
 
points = svg.selectAll(".point") 
 
    .data(data) 
 
    .enter().append("path") 
 
    .attr("class", "point") 
 
    .attr("d", d3.svg.symbol().type("triangle-up")) 
 
    .attr("transform", function(d){ 
 
     return "translate("+x(d.x)+","+y(d.y)+")"; 
 
    }) 
 
    // hide all points expect default group 
 
    .style('opacity', function(d){ return d.group == groups[0]?1:0; });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.3.13/d3.min.js"></script>

+0

谢谢@PierreB!这非常有帮助。我一直在研究整个周末,无法弄清楚这一点。我很欣赏你帮助我的时间。 –

+0

不客气:-) – PierreB

3

您有一个好的开始在这里!为了使这更好,你需要三件事。用于选择组的UI组件,用于检测此组件中的更改的事件侦听器,以及用于处理可视化更新的功能。

在我添加的代码中,我为d3生命周期的每个部分创建了三个新函数。输入将新元素附加到我们的图形的句柄。根据绑定数据的更改更新现有值。退出删除不再有数据绑定到他们的任何元素。阅读Mike Bostock在该链接的经典文章https://bost.ocks.org/mike/join/以获取更多信息。借助此功能,您可以灵活地为图表添加很酷的转换,还可以自定义数据输入和退出的方式。

var data = [{ group: 1, x: 5.5, y: 0 }, { group: 1, x: 0, y: 6 }, { group: 1, x: 7.5, y: 8 }, { group: 2, x: 4.5, y: 4 }, { group: 2, x: 4.5, y: 2 }, { group: 3, x: 4, y: 4 }]; 
 

 
var margin = {top: 20, right: 20, bottom: 30, left: 40}, 
 
    width = 960 - margin.left - margin.right, 
 
    height = 500 - margin.top - margin.bottom; 
 

 
var x = d3.scale.linear() 
 
    .range([0, width]); 
 

 
var y = d3.scale.linear() 
 
    .range([height, 0]); 
 
    
 

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

 
    
 
// Coerce the strings to numbers. 
 
data.forEach(function(d) { 
 
    d.x = +d.x; 
 
    d.y = +d.y; 
 
}); 
 

 
// Compute the scales’ domains. 
 
x.domain(d3.extent(data, function(d) { return d.x; })).nice(); 
 
y.domain(d3.extent(data, function(d) { return d.y; })).nice(); 
 

 

 
// Add the x-axis. 
 
svg.append("g") 
 
    .attr("class", "x axis") 
 
    .attr("transform", "translate(0," + height + ")") 
 
    .call(d3.svg.axis().scale(x).orient("bottom")); 
 

 
// Add the y-axis. 
 
svg.append("g") 
 
    .attr("class", "y axis") 
 
    .call(d3.svg.axis().scale(y).orient("left")); 
 

 
// Get a subset of the data based on the group 
 
function getFilteredData(data, group) { 
 
\t return data.filter(function(point) { return point.group === parseInt(group); }); 
 
} 
 

 
// Helper function to add new points to our data 
 
function enterPoints(data) { 
 
    // Add the points! 
 
    svg.selectAll(".point") 
 
    .data(data) 
 
    .enter().append("path") 
 
    .attr("class", "point") 
 
    .attr('fill', 'red') 
 
    .attr("d", d3.svg.symbol().type("triangle-up")) 
 
    .attr("transform", function(d) { return "translate(" + x(d.x) + "," + y(d.y) + ")"; }); 
 
} 
 

 
function exitPoints(data) { 
 
    svg.selectAll(".point") 
 
     .data(data) 
 
     .exit() 
 
     .remove(); 
 
} 
 

 
function updatePoints(data) { 
 
    svg.selectAll(".point") 
 
     .data(data) 
 
     .transition() 
 
\t .attr("transform", function(d) { return "translate(" + x(d.x) + "," + y(d.y) + ")"; }); 
 
} 
 

 
// New select element for allowing the user to select a group! 
 
var $groupSelector = document.querySelector('.group-select'); 
 
var groupData = getFilteredData(data, $groupSelector.value); 
 

 
// Enter initial points filtered by default select value set in HTML 
 
enterPoints(groupData); 
 

 
$groupSelector.onchange = function(e) { 
 
    var group = e.target.value; 
 
    var groupData = getFilteredData(data, group); 
 

 
    updatePoints(groupData); 
 
    enterPoints(groupData); 
 
    exitPoints(groupData); 
 

 
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 
 
<label> 
 
    Group 
 
    <select class="group-select"> 
 
    <option value=1 selected>1</option> 
 
    <option value=2>2</option> 
 
    <option value=3>3</option> 
 
    </select> 
 
</label>