Javascript 为什么`treemap.nodes`看不到对我的对象的更新?
我正在用d3.js做一个树形图布局。我的树的叶节点比我想象的多得多,因此我希望修剪树以保持每个分支的叶节点百分比,但将叶的总数减少到一些小的Javascript 为什么`treemap.nodes`看不到对我的对象的更新?,javascript,json,d3.js,Javascript,Json,D3.js,我正在用d3.js做一个树形图布局。我的树的叶节点比我想象的多得多,因此我希望修剪树以保持每个分支的叶节点百分比,但将叶的总数减少到一些小的n 我已经成功地实现了一个for循环,它以所需的方式修剪数据对象的子对象,但是当我调用treemap.nodes(data)时,我会得到一个以原始节点数作为返回值的列表,而不是一个减少了叶子数的节点列表 这里有一个简单的例子重现了这个问题 <!DOCTYPE html> <html> <head> <meta htt
n
我已经成功地实现了一个for循环,它以所需的方式修剪数据
对象的子对象,但是当我调用treemap.nodes(data)
时,我会得到一个以原始节点数作为返回值的列表,而不是一个减少了叶子数的节点列表
这里有一个简单的例子重现了这个问题
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
</head>
<body>
<script type="text/javascript">
var w = 1280 - 80,
h = 800 - 180;
// Declare treemap
var treemap = d3.layout.treemap()
.round(false)
.size([w, h])
.sticky(true)
.value(function(d) { return d.size; });
// Load data
d3.json("demo.json", function(data) {
// Trim data
var categories = treemap.nodes(data)
.filter(function(d) { return d.depth==1; });
n = 10; //This is the maximum number of leaves I want to have
var total_value = treemap.nodes(data)[0].value;
for(var vertex of categories)
{
var num_children = vertex.children.length;
var percentage_screen = num_children / total_value;
var max_leaves = Math.max(1, Math.floor(n * percentage_screen));
vertex.children = vertex.children.slice(0,max_leaves)
}
// Here I try to get a list of the leaves
var nodes = treemap.nodes(data)
.filter(function(d) { return !d.children; });
// This print statement prints 20, the original number of leaves
console.log(nodes.length);
// But if I recursively count the number of leaves, I get the new smaller number, 10
console.log(recursive_node_counter(data));
});
function recursive_node_counter(d){
if('children' in d){
var num_child = 0;
for(child of d.children){
num_child += recursive_node_counter(child);
}
return num_child;
} else {
return 1
}
};
</script>
</body>
</html>
为什么
treemap.nodes(data)
看不到data
变量的更改 以下控制台语句更能说明问题:
d3.json("./demo.json", function(data) {
// Trim data
var categories = treemap.nodes(data)
.filter(function(d) { return d.depth==1; });
n = 10; //This is the maximum number of leaves I want to have
var total_value = treemap.nodes(data)[0].value;
for(var vertex of categories)
{
var num_children = vertex.children.length;
var percentage_screen = num_children / total_value;
var max_leaves = Math.max(1, Math.floor(n * percentage_screen));
vertex.children = vertex.children.slice(0,max_leaves);
}
// Here I try to get a list of the leaves
console.log(data);
var nodes = treemap.nodes(data)
.filter(function(d) { return !d.children; });
console.log(data);
});
当我们运行这段代码时,我们会得到相同的意外输出
20
10
为什么?如果我们查看treemap.nodes(数据)调用,就会清楚:
function treemap(d) {
var nodes = stickies || hierarchy(d), root = nodes[0];
root.x = 0;
root.y = 0;
root.dx = size[0];
root.dy = size[1];
if (stickies) hierarchy.revalue(root);
scale([ root ], root.dx * root.dy / root.value);
(stickies ? stickify : squarify)(root);
if (sticky) stickies = nodes;
return nodes;
}
...
...
hierarchy.revalue = function(root) {
if (value) {
d3_layout_hierarchyVisitBefore(root, function(node) {
if (node.children) node.value = 0;
});
d3_layout_hierarchyVisitAfter(root, function(node) {
var parent;
if (!node.children) node.value = +value.call(hierarchy, node, node.depth) || 0;
if (parent = node.parent) parent.value += node.value;
});
}
return root;
};
在第一次调用treemap.nodes(数据)时,将粘滞设置为未修剪的数据。在第二次调用treemap.nodes(data)时,函数通过“stickies”变量使用第一次调用的数据。在同一个第二次调用中,该函数随后调用hierarchy.revalue(root)对传入的修剪数据进行重新评估,从而更新相关对象。以下控制台语句更能说明此问题:
d3.json("./demo.json", function(data) {
// Trim data
var categories = treemap.nodes(data)
.filter(function(d) { return d.depth==1; });
n = 10; //This is the maximum number of leaves I want to have
var total_value = treemap.nodes(data)[0].value;
for(var vertex of categories)
{
var num_children = vertex.children.length;
var percentage_screen = num_children / total_value;
var max_leaves = Math.max(1, Math.floor(n * percentage_screen));
vertex.children = vertex.children.slice(0,max_leaves);
}
// Here I try to get a list of the leaves
console.log(data);
var nodes = treemap.nodes(data)
.filter(function(d) { return !d.children; });
console.log(data);
});
当我们运行这段代码时,我们会得到相同的意外输出
20
10
为什么?如果我们查看treemap.nodes(数据)调用,就会清楚:
function treemap(d) {
var nodes = stickies || hierarchy(d), root = nodes[0];
root.x = 0;
root.y = 0;
root.dx = size[0];
root.dy = size[1];
if (stickies) hierarchy.revalue(root);
scale([ root ], root.dx * root.dy / root.value);
(stickies ? stickify : squarify)(root);
if (sticky) stickies = nodes;
return nodes;
}
...
...
hierarchy.revalue = function(root) {
if (value) {
d3_layout_hierarchyVisitBefore(root, function(node) {
if (node.children) node.value = 0;
});
d3_layout_hierarchyVisitAfter(root, function(node) {
var parent;
if (!node.children) node.value = +value.call(hierarchy, node, node.depth) || 0;
if (parent = node.parent) parent.value += node.value;
});
}
return root;
};
在第一次调用treemap.nodes(数据)时,将粘滞设置为未修剪的数据。在第二次调用treemap.nodes(data)时,函数通过“stickies”变量使用第一次调用的数据。在同一个第二次调用中,该函数随后调用hierarchy.revalue(root)对传入的修剪数据进行重新评估,从而更新相关对象。以下控制台语句更能说明此问题:
d3.json("./demo.json", function(data) {
// Trim data
var categories = treemap.nodes(data)
.filter(function(d) { return d.depth==1; });
n = 10; //This is the maximum number of leaves I want to have
var total_value = treemap.nodes(data)[0].value;
for(var vertex of categories)
{
var num_children = vertex.children.length;
var percentage_screen = num_children / total_value;
var max_leaves = Math.max(1, Math.floor(n * percentage_screen));
vertex.children = vertex.children.slice(0,max_leaves);
}
// Here I try to get a list of the leaves
console.log(data);
var nodes = treemap.nodes(data)
.filter(function(d) { return !d.children; });
console.log(data);
});
当我们运行这段代码时,我们会得到相同的意外输出
20
10
为什么?如果我们查看treemap.nodes(数据)调用,就会清楚:
function treemap(d) {
var nodes = stickies || hierarchy(d), root = nodes[0];
root.x = 0;
root.y = 0;
root.dx = size[0];
root.dy = size[1];
if (stickies) hierarchy.revalue(root);
scale([ root ], root.dx * root.dy / root.value);
(stickies ? stickify : squarify)(root);
if (sticky) stickies = nodes;
return nodes;
}
...
...
hierarchy.revalue = function(root) {
if (value) {
d3_layout_hierarchyVisitBefore(root, function(node) {
if (node.children) node.value = 0;
});
d3_layout_hierarchyVisitAfter(root, function(node) {
var parent;
if (!node.children) node.value = +value.call(hierarchy, node, node.depth) || 0;
if (parent = node.parent) parent.value += node.value;
});
}
return root;
};
在第一次调用treemap.nodes(数据)时,将粘滞设置为未修剪的数据。在第二次调用treemap.nodes(data)时,函数通过“stickies”变量使用第一次调用的数据。在同一个第二次调用中,该函数随后调用hierarchy.revalue(root)对传入的修剪数据进行重新评估,从而更新相关对象。以下控制台语句更能说明此问题:
d3.json("./demo.json", function(data) {
// Trim data
var categories = treemap.nodes(data)
.filter(function(d) { return d.depth==1; });
n = 10; //This is the maximum number of leaves I want to have
var total_value = treemap.nodes(data)[0].value;
for(var vertex of categories)
{
var num_children = vertex.children.length;
var percentage_screen = num_children / total_value;
var max_leaves = Math.max(1, Math.floor(n * percentage_screen));
vertex.children = vertex.children.slice(0,max_leaves);
}
// Here I try to get a list of the leaves
console.log(data);
var nodes = treemap.nodes(data)
.filter(function(d) { return !d.children; });
console.log(data);
});
当我们运行这段代码时,我们会得到相同的意外输出
20
10
为什么?如果我们查看treemap.nodes(数据)调用,就会清楚:
function treemap(d) {
var nodes = stickies || hierarchy(d), root = nodes[0];
root.x = 0;
root.y = 0;
root.dx = size[0];
root.dy = size[1];
if (stickies) hierarchy.revalue(root);
scale([ root ], root.dx * root.dy / root.value);
(stickies ? stickify : squarify)(root);
if (sticky) stickies = nodes;
return nodes;
}
...
...
hierarchy.revalue = function(root) {
if (value) {
d3_layout_hierarchyVisitBefore(root, function(node) {
if (node.children) node.value = 0;
});
d3_layout_hierarchyVisitAfter(root, function(node) {
var parent;
if (!node.children) node.value = +value.call(hierarchy, node, node.depth) || 0;
if (parent = node.parent) parent.value += node.value;
});
}
return root;
};
在第一次调用treemap.nodes(数据)时,将粘滞设置为未修剪的数据。在第二次调用treemap.nodes(data)时,函数通过“stickies”变量使用第一次调用的数据。在同一个第二次调用中,该函数随后调用hierarchy.revalue(root)对传入的修剪数据进行重新评估,从而更新相关对象。我的观点是,d3是数据驱动的,因此与其试图攻击布局对象,不如在将数据连接到布局之前修改数据 一种解决方案是:使用草稿行版本的数据和树映射来获得树映射行为的好处来进行修剪,然后使用修改后的数据创建一个新实例
var w = 1280 - 80,
h = 800 - 180;
// Load data
d3.json("demo.json", function (data) {
// make a temp object to use treemap behaviour
var treemap = d3.layout.treemap()
.sticky(true)
.value(function (d) { return d.size; }),
// cache original data
tempData = $.extend(true, {}, data),
//***snap shot 1
// Trim original data using temp data
tempNodesData = treemap.nodes(tempData),
//***snap shot 2
total_value = tempNodesData[0].value,
categories = tempNodesData
.filter(function (d) { return d.depth == 1; }),
n = 10; //This is the maximum number of leaves I want to have
categories.forEach(function (vertex, i, categories) {
var num_children = vertex.children.length,
percentage_screen = num_children / total_value,
max_leaves = Math.max(1, Math.floor(n * percentage_screen));
data.children[i].children = vertex.children.slice(0,max_leaves)
})
// re-Declare treemap
var treemap = d3.layout.treemap()
.round(false)
.size([w, h])
.sticky(true)
.value(function (d) { return d.size; }),
// Here I try to get a list of the leaves
nodes = treemap.nodes(data)
.filter(function(d) { return !d.children; });
// This print statement prints 20, the original number of leaves
alert('nodes.length: ' + nodes.length + '\n' + 'recursive_node_counter: ' + recursive_node_counter(data));
d3.select('body').insert('div', 'script').attr('class', 'logWindow').style({'color': 'red;'})
.html('nodes.length: ' + nodes.length + '</br>' + 'recursive_node_counter: ' + recursive_node_counter(data));
});
function recursive_node_counter(d){
if('children' in d){
var num_child = 0;
d.children.forEach( function(child){
num_child += recursive_node_counter(child);
})
return num_child;
} else {
return 1
}
};
var w=1280-80,
h=800-180;
//加载数据
d3.json(“demo.json”),函数(数据){
//创建一个临时对象以使用树映射行为
var treemap=d3.layout.treemap()
.粘性(真)
.value(函数(d){返回d.size;}),
//缓存原始数据
tempData=$.extend(true,{},data),
//***快照1
//使用临时数据修剪原始数据
tempNodesData=树映射节点(tempData),
//***快照2
total_value=tempNodesData[0]。值,
类别=临时节点数据
.filter(函数(d){返回d.depth==1;}),
n=10;//这是我想要的最大叶子数
类别。forEach(函数(顶点,i,类别){
var num_children=vertex.children.length,
百分比屏幕=子项数/总值,
max_leaves=Math.max(1,Math.floor(n*百分比屏幕));
data.children[i].children=vertex.children.slice(0,最大叶数)
})
//重新声明树映射
var treemap=d3.layout.treemap()
.round(假)
.尺寸([w,h])
.粘性(真)
.value(函数(d){返回d.size;}),
//在这里,我试图得到一份树叶的清单
节点=树映射节点(数据)
.filter(函数(d){return!d.children;});
//此打印语句打印20张,即原始的页数
警报('nodes.length:'+nodes.length+'\n'+'recursive_node_计数器:'+recursive_node_计数器(数据));
d3.select('body')。insert('div','script')。attr('class','logWindow')。style({'color':'red;'})
.html('nodes.length:'+nodes.length+''+'recursive_node_计数器:'+recursive_node_计数器(数据));
});
函数递归\u节点\u计数器(d){
if(d中的“儿童”){
var num_child=0;
d、 children.forEach(函数(child){
num_child+=递归_节点_计数器(child);
})
返回num_子项;
}否则{
返回1
}
};
作为对下面评论的回应,tempData
最初看起来是这样的:
在treemap.nodes(tempData)
语句之后
如果我保持数据的原始形式,那么我就不必浪费时间去弄清楚额外的属性是否重要(现在和将来!)我的观点是,d3是数据驱动的,所以与其试图破解布局对象,它总是更好