Javascript 在d3.js中,跳过空数据的append()
我正在用小圆圈的子弹画一个线图。但是,数据中有漏洞,在我的数组中用null表示。当然,没有数据的地方不应该有圆圈。但是d3的append()方法还是添加了它们。我如何避免这种情况 这是一个复制我的问题 我感兴趣的是不要在我的图形的X轴上有一系列的圆,因为它们都是空的 来自JSFIDLE链接的相关代码:Javascript 在d3.js中,跳过空数据的append(),javascript,d3.js,Javascript,D3.js,我正在用小圆圈的子弹画一个线图。但是,数据中有漏洞,在我的数组中用null表示。当然,没有数据的地方不应该有圆圈。但是d3的append()方法还是添加了它们。我如何避免这种情况 这是一个复制我的问题 我感兴趣的是不要在我的图形的X轴上有一系列的圆,因为它们都是空的 来自JSFIDLE链接的相关代码: svg.selectAll('circle').data(values).enter() .append('circle')// <-- I don't want to do this
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)
svg.selectAll('circle')。数据(值)。输入()
.append('circle')/只需过滤它
values.filter(function(el){return el !== null;})
一种选择是以不同的方式表示数据,这样您就不必依赖索引来计算x坐标。例如,如果将每个基准表示为一个对象(例如,{x:0,y:0.2840042}
),则可以将x坐标计算为x(d.x)
,而不是x(i)
另一个选项是,当值为null时,将半径设置为零,因此圆是隐藏的:circle.attr(“r”,function(d){return d==null?0:3;})
。或者,您可以隐藏圆圈:circle.style(“display”,function(d){returnd==null?“none”:null;})
您还可以在附加空元素之后删除它们:circle.filter(函数(d){return d==null;})。remove()
。这对于最初的创建是可行的,但我不建议这样做,因为如果您以后重新选择元素,索引将发生更改。试试这种模式,它可以删除或隐藏您的圆圈
// 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();
最简单的选择是从传递到.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
请注意,您也可以按照此模式创建单个子元素,即使它们不是列表。例如,考虑一种情况,您希望有条件地添加第二个循环:
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 },
})
var圆=[
{颜色:'红色',cx:30,cy:30,亚圆形:'蓝色'},
{颜色:'蓝色',cx:60,cy:60,亚圆形:'绿色'},
{颜色:'绿色',cx:90,cy:90},
];
//创建一个包含圆圈的组,因为结果是
//是:
//
//
//
//
var circlesGroups=svg.selectAll(“g.circles”)
.数据(圆圈)
.输入()
.append(“g”).attr({“class”:“circles”})
//将第一个圆添加到组中
圈群
.append(“圆圈”).attr({
“fill”:函数(d){return d.color},
“r”:20,
“cx”:函数(d){返回d.cx},
“cy”:函数(d){返回d.cy},
})
//如果存在子圆颜色,请将第二个圆添加到组中
圆圈组。选择全部(“圆圈.子圆圈”)
.数据(功能(d){
if(d.亚圆形颜色)
返回[d];
返回[];
})
.输入()
.append(“圆圈”).attr({
“类”:“子圈”,
“fill”:函数(d){返回d.subCircleColor;},
“r”:10,
“cx”:函数(d){返回d.cx},
“cy”:函数(d){返回d.cy},
})
Fiddle:如果你一开始就不想附加它,这里有一种方法。我在.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();
}
});
这是一个bin谢谢,但它只是从数组中删除了这些元素,这会影响传递到attr()设置函数的索引i。我需要指数保持不变,因为这是我用来计算x位置的东西。这实际上是我的问题,我觉得自己很傻,甚至连过滤都不考虑。我想我是被“d3是如何做到这一点的?”迷住了,以至于我没有想到:)撇开不谈,关于零半径方法——使用我的大而稀疏的数组,当我创建并使用一个新的过滤数组时,我获得了更好的性能。我意识到@meetamit希望保持原始指数,但我想指出可能存在不理想的性能影响。当我使用circle.filter(函数(d){return d==null;})时,d3可能通过短路来解决这个问题。remove()
方法解决了我的问题,它工作得很好!虽然这跳过了附加
,但它仍然将
附加为容器-当d
为0时,它将保留为空。如果您还想在
中附加其他元素,那么这可能是有利的,但它实际上并没有跳过附加
。另外,在.selectAll('z')
中,它应该是.selectAll('g')
,否则重复调用此代码(即使使用相同的数据
)将每次附加
元素。感谢您的审阅。如果没有d,添加一个else来删除g怎么样?“else{d3.select(this).remove()}”Yes-调用.remove()
的结果是数据中的非零数量与
的数量相同。它还使i
与d
在数据中的位置保持同步。但是,根据更大的背景,这可能会有问题。例如,如果要对此.data()
联接的更新或退出结果调用附加函数(例如.attr
或.remove
),则可能会出现错误,因为某些元素已被删除。另外,如果您稍后重新选择all()
这些
并用数据重新连接它们,i
可能不再与d
的数组位置同步。如果不进行测试,我不确定我指出的问题示例是否会如所述实际发生。我的主要假设是,如果您曾经.remove()
d3选择中的一个成员没有使用现有的选择,那么您可能会遇到问题。自从我发布这个问题(5年前,geez)以来,我基本上采纳了mbostock的建议(在本页上),几乎从不依赖I
来获取数据