javascript 在 d3.js 中,为空数据跳过 append()
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10826180/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
In d3.js, skip append() for null data
提问by meetamit
I'm drawing a line graph out of little circle bullets. However, the data has holes in it, which are represented by null's in my array. Naturally, wherever there's no data, there shouldn't be circles. But d3's append() method adds them anyway. How do I avoid this?
我正在用小圆圈符号绘制折线图。但是,数据中有漏洞,在我的数组中由空值表示。自然,哪里没有数据,哪里就不应该有圆圈。但是 d3 的 append() 方法无论如何都会添加它们。我如何避免这种情况?
Here's a jsFiddle mockupreproducing my problem exactly.
这是一个jsFiddle 模型,准确地再现了我的问题。
I'm interested in NOT having that series of circles that lie on the X axis of my graph, since those are all nulls.
我对没有位于图表 X 轴上的那一系列圆圈感兴趣,因为这些都是空值。
Relevant code from the jsfiddle link:
来自 jsfiddle 链接的相关代码:
svg.selectAll('circle').data(values).enter()
.append('circle')// <-- I don't want to do this for null's
.attr('fill', '#c00')
.attr('r', 3)
.attr('cx', xi)
.attr('cy', yFlipped)
回答by mbostock
One option is to represent your data differently, so that you aren't dependent on the index to compute the x-coordinate. For example, if you represented each datum as an object (e.g., {x: 0, y: 0.2840042}
) then you could compute the x-coordinate as x(d.x)
rather than x(i)
.
一种选择是以不同方式表示您的数据,以便您不依赖于索引来计算 x 坐标。例如,如果您将每个数据表示为一个对象(例如{x: 0, y: 0.2840042}
),那么您可以将 x 坐标计算为x(d.x)
而不是x(i)
。
Another option would be to set the radius to zero when the value is null, so the circles are hidden: circle.attr("r", function(d) { return d == null ? 0 : 3; })
. Or, you could hide the circles: circle.style("display", function(d) { return d == null ? "none" : null; })
.
另一种选择是在值为 null 时将半径设置为零,以便隐藏圆圈:circle.attr("r", function(d) { return d == null ? 0 : 3; })
。或者,您可以隐藏圆圈:circle.style("display", function(d) { return d == null ? "none" : null; })
。
You could also remove the null elements after appending them: circle.filter(function(d) { return d == null; }).remove()
. That would work for the initial creation, but I wouldn't recommend it because the index would change if you reselected the elements later.
您还可以在附加它们后删除空元素:circle.filter(function(d) { return d == null; }).remove()
。这适用于最初的创建,但我不推荐它,因为如果您稍后重新选择元素,索引会发生变化。
回答by David Wolever
The simplest option is to filter the nulls out of the data being passed in to .data(…)
, augmenting the data to maintain the index:
最简单的选择是从传入的数据中过滤掉空值.data(…)
,增加数据以维护索引:
svg.selectAll('circle')
.data(values
.map(function(v, idx) { return v == null? null : { idx: idx, value: v })
.filter(function(v) { return v != null })
)
.enter()
.append('circle')
.attr('fill', '#c00')
.attr('r', 3)
.attr('cx', function(d) { return d.idx * 10 }) // or whatever
.attr('cy', function(d) { return d.value.y }) // or whatever
Note that you can also follow this pattern individual sub-elements, even if they aren't naturally lists. For example, consider a situation where you want to conditionally add a second circle:
请注意,您也可以遵循此模式单独的子元素,即使它们不是自然的列表。例如,考虑一种情况,您希望有条件地添加第二个圆圈:
var circles = [
{ color: 'red', cx: 30, cy: 30, subCircleColor: 'blue' },
{ color: 'blue', cx: 60, cy: 60, subCircleColor: 'green' },
{ color: 'green', cx: 90, cy: 90 },
];
// Create a group which will hold the circles, since the result will
// be:
// <g class="circles">
// <circle color="{{ color }}" ... />
// <circle class="sub-circle" color="{{ subCircleColor }}" ... />
// </g>
var circlesGroups = svg.selectAll("g.circles")
.data(circles)
.enter()
.append("g").attr({"class": "circles"})
// Add the first circle to the group
circlesGroups
.append("circle").attr({
"fill": function(d) { return d.color },
"r": 20,
"cx": function(d) { return d.cx },
"cy": function(d) { return d.cy },
})
// If there is a subCircleColor, add the second circle to the group
circlesGroups.selectAll("circle.sub-circle")
.data(function(d) {
if (d.subCircleColor)
return [d];
return [];
})
.enter()
.append("circle").attr({
"class": "sub-circle",
"fill": function(d) { return d.subCircleColor; },
"r": 10,
"cx": function(d) { return d.cx },
"cy": function(d) { return d.cy },
})
Fiddle: http://jsfiddle.net/3d6e648k/
回答by getsetbro
Here is a way if you want to never append it in the first place. I used an if statement inside an .each() and then d3.select(this) to append it to the current item.
如果您不想一开始就附加它,这是一种方法。我在 .each() 中使用了 if 语句,然后使用 d3.select(this) 将其附加到当前项目。
var data = [9, 0, 7, 0, 5, 0, 3, 0, 1];
var svg = d3.select('#svg').append('svg').attr({'viewBox': '-10 -10 99 20'});
svg.selectAll('g').data(data).enter().append('g').each(function (d,i) {
if(d){
d3.select(this).append('circle').attr({r:5,cx:(i*9)});
}else{
d3.select(this).remove();
}
});
Here is a bin http://jsbin.com/qojifug/edit?js,output
回答by Monarch Wadia
Try this pattern, which can either delete or hide your circles.
试试这个模式,它可以删除或隐藏你的圈子。
// Step 1: hides all circles which are "null"
d3.selectAll(".yourItem")
.data(data)
.enter()
.append("circle")
.attr("visibility", function(d,i){
if(yourFunction(d) == null) return "hidden";
})
// Step 2: optional, deletes all circles which are "hidden"
d3.selectAll("circle[visibility=hidden]").remove();
回答by xdazz
Just filter it.
过滤一下就好了
values.filter(function(el){return el !== null;})