任何人都可以向我解释为什么这两个表达式返回不同的值...
log1.text(c20(1)); // "#aec7e8"
log2.text(d3.scale.category20()(1)); // "#1f77b4"
...在以下上下文中
工作示例...
var c20 = d3.scale.category20(),
col = d3.range(20).map(function(c) {
return c20(c).replace("#", "0x")
}),
log1 = d3.select("#log1"),
log2 = d3.select("#log2");
log1.text(c20(1)); // "#aec7e8"
log2.text(d3.scale.category20()(1)); // "#1f77b4"
$("#user-agent").text(navigator.userAgent);
#log div {
display: inline-block;
margin: 0 0 0 10px;
background: #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<div id="log">
<div id="log1"></div>
<div id="log2"></div>
</div>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="container"></div>
<p id="user-agent"></p>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<div id="log1"></div>
<div id="log2"></div>
</body>
</html>
我的系统中报告的用户代理是
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36
我有点明白上面的行为,但这很奇怪......
这是为什么...
// method 1
d3.range(20).map(d3.scale.category20())
0 #1f77b4
1 #aec7e8
2 #ff7f0e
3 #ffbb78
4 #2ca02c
5 #98df8a
6 #d62728
7 #ff9896
8 #9467bd
9 #c5b0d5
10 #8c564b
11 #c49c94
12 #e377c2
13 #f7b6d2
14 #7f7f7f
15 #c7c7c7
16 #bcbd22
17 #dbdb8d
18 #17becf
19 #9edae5
与此不同...
// method 2
d3.range(20).map(function(d, i) {
return d3.scale.category20()(i);
})
0 #1f77b4
1 #1f77b4
2 #1f77b4
3 #1f77b4
4 #1f77b4
5 #1f77b4
6 #1f77b4
7 #1f77b4
8 #1f77b4
9 #1f77b4
10 #1f77b4
11 #1f77b4
12 #1f77b4
13 #1f77b4
14 #1f77b4
15 #1f77b4
16 #1f77b4
17 #1f77b4
18 #1f77b4
19 #1f77b4
var c20 = d3.scale.category20(),
log1 = d3.select("#log1"),
log2 = d3.select("#log2");
log1.text(c20(1)); // "#aec7e8"
log2.text(d3.scale.category20()(1)); // "#1f77b4"
d3.select("#t1").selectAll(".logs")
.data(d3.range(20).map(d3.scale.category20()))
.enter().append("tr").selectAll("td").data(function(d) {
return [d]
})
.enter().append("td")
.attr("class", "logs")
.text(function(d, i, j) {
return [j, d].join("\t")
})
d3.select("#t2").selectAll(".logs")
.data(d3.range(20).map(function(d, i) {
return d3.scale.category20()(i);
}))
.enter().append("tr").selectAll("td").data(function(d) {
return [d]
})
.enter().append("td")
.attr("class", "logs")
.text(function(d, i, j) {
return [j, d].join("\t")
})
#log div {
display: inline-block;
margin: 0 0 10px 10px;
background: #ccc;
}
#t1,
#t2 {
background: #ccc;
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<div id="log">
<div id="log1"></div>
<div id="log2"></div>
</div>
<div id="t1"></div>
<div id="t2"></div>
只是为了解释一下,我想使用上面方法 2 的原因是因为我需要将十六进制字符串转换为格式正确的十六进制数字,所以我必须在途中处理域值。实际用例是这样的:
var col = d3.range(20).map(function(c){
return d3.scale.category20()(c).replace("#", "0x")
});
这是行不通的(我仍然不明白为什么不行),这就是我必须这样做的原因:
var c20 = d3.scale.category20(),
col = d3.range(20).map(function(c){
return c20(c).replace("#", "0x")
});
最佳答案
您可以认为调色板在使用过程中“不断增加”。如果您在顶部创建调色板,例如
var palette = d3.scale.category20();
并在迭代中应用调色板不同的值(例如
selection.style('fill', function(d, i) {return palette(i);});
然后在每次调用时,调色板检查它是否已经为该值分配了颜色;如果没有,它会尝试提供一种新颜色(或者如果颜色用完则回收)。
相比之下,如果您在迭代中将值应用到一个新的调色板,它总是只会从那个特定的调色板中提取一个值:
selection.style('fill', function(d, i) {return d3.scale.category20()(i);});
不良结果是所有颜色都相同。
换句话说,d3.scale.category20
不是纯函数;它隐含地跟踪它的状态。它类似于例如使用接受种子的随机数生成,即确定性:您不想在迭代中重新创建它,否则您提取的随机数将始终相同。
这个问题(D3v4
之前)说明了函数式编程的一般值(value),因为预计使用某些值调用的函数将始终仅依赖于提供的参数,这也使测试更容易。
关于javascript - d3.scale.category20 对我来说太聪明了,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32422325/